diff --git a/app/controllers/my_profile/cms_controller.rb b/app/controllers/my_profile/cms_controller.rb
index 61454e4..1feb652 100644
--- a/app/controllers/my_profile/cms_controller.rb
+++ b/app/controllers/my_profile/cms_controller.rb
@@ -44,7 +44,7 @@ class CmsController < MyProfileController
Event
]
parent_id = params ? params[:parent_id] : nil
- if !parent_id or !Article.find(parent_id).blog?
+ if !parent_id or !Article.find(parent_id).has_posts?
articles += [
RssFeed
]
@@ -56,13 +56,13 @@ class CmsController < MyProfileController
end
def special_article_types
- [Folder, Blog, UploadedFile]
+ [Folder, Blog, UploadedFile, Forum, Gallery]
end
def view
@article = profile.articles.find(params[:id])
conditions = []
- if @article.blog?
+ if @article.has_posts?
conditions = ['type != ?', 'RssFeed']
end
diff --git a/app/controllers/public/content_viewer_controller.rb b/app/controllers/public/content_viewer_controller.rb
index 483442a..56d93da 100644
--- a/app/controllers/public/content_viewer_controller.rb
+++ b/app/controllers/public/content_viewer_controller.rb
@@ -77,7 +77,7 @@ class ContentViewerController < ApplicationController
remove_comment
end
- if @page.blog?
+ if @page.has_posts?
posts = if params[:year] and params[:month]
filter_date = DateTime.parse("#{params[:year]}-#{params[:month]}-01")
@page.posts.by_range(filter_date..filter_date.at_end_of_month)
@@ -88,7 +88,7 @@ class ContentViewerController < ApplicationController
@posts = posts.paginate({ :page => params[:npage], :per_page => @page.posts_per_page }.merge(Article.display_filter(user, profile)))
end
- if @page.folder? && @page.view_as == 'image_gallery'
+ if @page.folder? && @page.gallery?
@images = @page.images
@images = @images.paginate(:per_page => per_page, :page => params[:npage]) unless params[:slideshow]
end
diff --git a/app/helpers/content_viewer_helper.rb b/app/helpers/content_viewer_helper.rb
index f990035..a835779 100644
--- a/app/helpers/content_viewer_helper.rb
+++ b/app/helpers/content_viewer_helper.rb
@@ -1,6 +1,7 @@
module ContentViewerHelper
include BlogHelper
+ include ForumHelper
def number_of_comments(article)
n = article.comments.size
diff --git a/app/helpers/forum_helper.rb b/app/helpers/forum_helper.rb
new file mode 100644
index 0000000..82bd870
--- /dev/null
+++ b/app/helpers/forum_helper.rb
@@ -0,0 +1,47 @@
+module ForumHelper
+
+ def cms_label_for_new_children
+ _('New discussion topic')
+ end
+
+ def cms_label_for_edit
+ _('Configure forum')
+ end
+
+ def list_forum_posts(articles)
+ pagination = will_paginate(articles, {
+ :param_name => 'npage',
+ :prev_label => _('« Newer posts'),
+ :next_label => _('Older posts »')
+ })
+ content = [content_tag('tr',
+ content_tag('th', _('Discussion topic')) +
+ content_tag('th', _('Posts')) +
+ content_tag('th', _('Last post'))
+ )
+ ]
+ artic_len = articles.length
+ articles.each_with_index{ |art,i|
+ css_add = [ 'position-'+(i+1).to_s() ]
+ position = (i%2 == 0) ? 'odd-post' : 'even-post'
+ css_add << 'first' if i == 0
+ css_add << 'last' if i == (artic_len-1)
+ css_add << 'not-published' if !art.published?
+ css_add << position
+ content << content_tag('tr',
+ content_tag('td', link_to(art.title, art.url)) +
+ content_tag('td', link_to(art.comments.count, art.url.merge(:anchor => 'comments_list'))) +
+ content_tag('td', last_topic_update(art)),
+ :class => 'forum-post ' + css_add.join(' '),
+ :id => "post-#{art.id}"
+ )
+ }
+ content_tag('table', content) + (pagination or '')
+ end
+
+ def last_topic_update(article)
+ last_update_at, last_update_by = (article.comments.count.zero? ? [article.updated_at, article.author] : [article.comments.last.created_at, article.comments.last.author])
+ time_ago_as_sentence(last_update_at) + ' ' + _('ago') + ' ' + _('by') + ' ' + link_to(last_update_by.name, last_update_by.url)
+ end
+
+end
diff --git a/app/models/article.rb b/app/models/article.rb
index f61cfc1..18dc027 100644
--- a/app/models/article.rb
+++ b/app/models/article.rb
@@ -237,6 +237,14 @@ class Article < ActiveRecord::Base
false
end
+ def forum?
+ false
+ end
+
+ def has_posts?
+ false
+ end
+
def published?
if self.published
if self.parent && !self.parent.published?
@@ -248,8 +256,9 @@ class Article < ActiveRecord::Base
end
end
- named_scope :published, :conditions => { :published => true }
- named_scope :folders, :conditions => { :type => ['Folder', 'Blog'] }
+ named_scope :published, :conditions => { :published => true }
+ named_scope :folders, :conditions => { :type => ['Folder', 'Blog', 'Forum', 'Gallery'] }
+ named_scope :galleries, :conditions => { :type => 'Gallery' }
named_scope :images, :conditions => { :is_image => true }
def self.display_filter(user, profile)
@@ -350,7 +359,7 @@ class Article < ActiveRecord::Base
false
end
- def display_as_gallery?
+ def gallery?
false
end
diff --git a/app/models/blog.rb b/app/models/blog.rb
index 09e6747..55d838d 100644
--- a/app/models/blog.rb
+++ b/app/models/blog.rb
@@ -1,15 +1,6 @@
class Blog < Folder
- has_many :posts, :class_name => 'Article', :foreign_key => 'parent_id', :source => :children, :conditions => [ 'articles.type != ?', 'RssFeed' ], :order => 'published_at DESC, id DESC'
-
- attr_accessor :feed_attrs
-
- after_create do |blog|
- blog.children << RssFeed.new(:name => 'feed', :profile => blog.profile)
- blog.feed = blog.feed_attrs
- end
-
- settings_items :posts_per_page, :type => :integer, :default => 5
+ acts_as_having_posts
def self.short_description
_('Blog')
@@ -35,21 +26,6 @@ class Blog < Folder
true
end
- def feed
- self.children.find(:first, :conditions => {:type => 'RssFeed'})
- end
-
- def feed=(attrs)
- if attrs
- if self.feed
- self.feed.update_attributes(attrs)
- else
- self.feed_attrs = attrs
- end
- end
- self.feed
- end
-
has_one :external_feed, :foreign_key => 'blog_id', :dependent => :destroy
attr_accessor :external_feed_data
@@ -78,17 +54,7 @@ class Blog < Folder
end
end
- def name=(value)
- self.set_name(value)
- if self.slug.blank?
- self.slug = self.name.to_slug
- else
- self.slug = self.slug.to_slug
- end
- end
-
settings_items :visualization_format, :type => :string, :default => 'full'
validates_inclusion_of :visualization_format, :in => [ 'full', 'short' ], :if => :visualization_format
-
end
diff --git a/app/models/folder.rb b/app/models/folder.rb
index 4a1138e..b31300e 100644
--- a/app/models/folder.rb
+++ b/app/models/folder.rb
@@ -2,23 +2,11 @@ class Folder < Article
acts_as_having_settings :field => :setting
- settings_items :view_as, :type => :string, :default => 'folder'
-
xss_terminate :only => [ :body ], :with => 'white_list', :on => 'validation'
include WhiteListFilter
filter_iframes :body, :whitelist => lambda { profile && profile.environment && profile.environment.trusted_sites_for_iframe }
- def self.select_views
- [[_('Folder'), 'folder'], [_('Image gallery'), 'image_gallery']]
- end
-
- def self.views
- select_views.map(&:last)
- end
-
- validates_inclusion_of :view_as, :in => self.views
-
def self.short_description
_('Folder')
end
@@ -31,33 +19,18 @@ class Folder < Article
'folder'
end
-
+ include ActionView::Helpers::TagHelper
def to_html(options = {})
- send(view_as)
- end
-
- def folder
folder = self
lambda do
render :file => 'content_viewer/folder', :locals => { :folder => folder }
end
end
- def image_gallery
- article = self
- lambda do
- render :file => 'content_viewer/image_gallery', :locals => {:article => article}
- end
- end
-
def folder?
true
end
- def display_as_gallery?
- view_as == 'image_gallery'
- end
-
def can_display_hits?
false
end
@@ -74,6 +47,6 @@ class Folder < Article
:foreign_key => 'parent_id',
:order => 'articles.type, articles.name',
:include => :reference_article,
- :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]
+ :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]
end
diff --git a/app/models/forum.rb b/app/models/forum.rb
new file mode 100644
index 0000000..916aaff
--- /dev/null
+++ b/app/models/forum.rb
@@ -0,0 +1,24 @@
+class Forum < Folder
+
+ acts_as_having_posts :order => 'updated_at DESC'
+
+ def self.short_description
+ _('Forum')
+ end
+
+ def self.description
+ _('An internet forum, also called message board, where discussions can be held.')
+ end
+
+ include ActionView::Helpers::TagHelper
+ def to_html(options = {})
+ lambda do
+ render :file => 'content_viewer/forum_page'
+ end
+ end
+
+ def forum?
+ true
+ end
+
+end
diff --git a/app/models/gallery.rb b/app/models/gallery.rb
new file mode 100644
index 0000000..a4307e3
--- /dev/null
+++ b/app/models/gallery.rb
@@ -0,0 +1,23 @@
+class Gallery < Folder
+
+ def self.short_description
+ _('Gallery')
+ end
+
+ def self.description
+ _('A gallery, inside which you can put images.')
+ end
+
+ include ActionView::Helpers::TagHelper
+ def to_html(options)
+ article = self
+ lambda do
+ render :file => 'content_viewer/image_gallery', :locals => {:article => article}
+ end
+ end
+
+ def gallery?
+ true
+ end
+
+end
diff --git a/app/models/organization.rb b/app/models/organization.rb
index 57590b3..122a77d 100644
--- a/app/models/organization.rb
+++ b/app/models/organization.rb
@@ -116,7 +116,7 @@ class Organization < Profile
def default_set_of_articles
[
Blog.new(:name => _('Blog')),
- Folder.new(:name => _('Gallery'), :view_as => 'image_gallery'),
+ Gallery.new(:name => _('Gallery')),
]
end
diff --git a/app/models/person.rb b/app/models/person.rb
index 20bf897..2ec53d6 100644
--- a/app/models/person.rb
+++ b/app/models/person.rb
@@ -223,7 +223,7 @@ class Person < Profile
def default_set_of_articles
[
Blog.new(:name => _('Blog')),
- Folder.new(:name => _('Gallery'), :view_as => 'image_gallery'),
+ Gallery.new(:name => _('Gallery')),
]
end
diff --git a/app/models/profile.rb b/app/models/profile.rb
index 8963ecc..820a673 100644
--- a/app/models/profile.rb
+++ b/app/models/profile.rb
@@ -525,7 +525,7 @@ private :generate_url, :url_options
# associated to the profile before being saved. Example:
#
# def default_set_of_articles
- # [Blog.new(:name => 'Blog'), Folder.new(:name => 'Gallery', :view_as => 'image_gallery')]
+ # [Blog.new(:name => 'Blog'), Gallery.new(:name => 'Gallery')]
# end
#
# By default, this method returns an empty array.
@@ -690,6 +690,16 @@ private :generate_url, :url_options
self.blogs.count.nonzero?
end
+ has_many :forums, :source => 'articles', :class_name => 'Forum'
+
+ def forum
+ self.has_forum? ? self.forums.first(:order => 'id') : nil
+ end
+
+ def has_forum?
+ self.forums.count.nonzero?
+ end
+
def admins
self.members_by_role(Profile::Roles.admin(environment.id))
end
@@ -703,7 +713,7 @@ private :generate_url, :url_options
end
def image_galleries
- folders.select { |folder| folder.display_as_gallery?}
+ articles.galleries
end
def blocks_to_expire_cache
diff --git a/app/models/rss_feed.rb b/app/models/rss_feed.rb
index 061c5a9..d848428 100644
--- a/app/models/rss_feed.rb
+++ b/app/models/rss_feed.rb
@@ -61,7 +61,7 @@ class RssFeed < Article
include ActionController::UrlWriter
def fetch_articles
- if parent && parent.blog?
+ if parent && parent.has_posts?
return parent.posts.find(:all, :conditions => ['published = ?', true], :limit => self.limit, :order => 'id desc')
end
diff --git a/app/models/slideshow_block.rb b/app/models/slideshow_block.rb
index c169cf7..29ab012 100644
--- a/app/models/slideshow_block.rb
+++ b/app/models/slideshow_block.rb
@@ -11,7 +11,7 @@ class SlideshowBlock < Block
end
def gallery
- gallery_id ? Folder.find(:first, :conditions => { :id => gallery_id }) : nil
+ gallery_id ? Gallery.find(:first, :conditions => { :id => gallery_id }) : nil
end
def public_filename_for(image)
diff --git a/app/models/uploaded_file.rb b/app/models/uploaded_file.rb
index c85a56c..d75b5f4 100644
--- a/app/models/uploaded_file.rb
+++ b/app/models/uploaded_file.rb
@@ -4,7 +4,7 @@
# of the file itself is kept. (FIXME?)
class UploadedFile < Article
- 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? }
+ 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? }
include ShortFilename
@@ -76,7 +76,7 @@ class UploadedFile < Article
article = self
if image?
lambda do
- if article.display_as_gallery? && options[:gallery_view]
+ if article.gallery? && options[:gallery_view]
images = article.parent.images
current_index = images.index(article)
total_of_images = images.count
@@ -119,7 +119,7 @@ class UploadedFile < Article
false
end
- def display_as_gallery?
- self.parent && self.parent.folder? && self.parent.display_as_gallery?
+ def gallery?
+ self.parent && self.parent.folder? && self.parent.gallery?
end
end
diff --git a/app/views/cms/_folder.rhtml b/app/views/cms/_folder.rhtml
index 0f09b7c..32331ef 100644
--- a/app/views/cms/_folder.rhtml
+++ b/app/views/cms/_folder.rhtml
@@ -1,6 +1,5 @@
<%= required_fields_message %>
<%= required f.text_field('name', :size => '64') %>
-<%= labelled_form_field(_('Folder type'), f.select(:view_as, Folder.select_views)) %>
<%= labelled_form_field(_('Description:'), text_area(:article, :body, :rows => 3, :cols => 64)) %>
diff --git a/app/views/cms/_forum.rhtml b/app/views/cms/_forum.rhtml
new file mode 100644
index 0000000..e143ba1
--- /dev/null
+++ b/app/views/cms/_forum.rhtml
@@ -0,0 +1,11 @@
+<%= error_messages_for 'forum' %>
+
+
<%= _('My Forum') %>
+
+<%= render :file => 'shared/tiny_mce' %>
+
+<%= required f.text_field(:name, :size => '64', :onchange => "updateUrlField(this, 'article_slug')") %>
+
+<%= labelled_form_field(_('Description:'), text_area(:article, :body, :cols => 64, :rows => 10)) %>
+
+<%= labelled_form_field(_('Posts per page:'), f.select(:posts_per_page, [5, 10, 20, 50, 100])) %>
diff --git a/app/views/cms/_gallery.rhtml b/app/views/cms/_gallery.rhtml
new file mode 100644
index 0000000..32331ef
--- /dev/null
+++ b/app/views/cms/_gallery.rhtml
@@ -0,0 +1,5 @@
+<%= required_fields_message %>
+
+<%= required f.text_field('name', :size => '64') %>
+
+<%= labelled_form_field(_('Description:'), text_area(:article, :body, :rows => 3, :cols => 64)) %>
diff --git a/app/views/cms/view.rhtml b/app/views/cms/view.rhtml
index a0e3e0f..0462ec5 100644
--- a/app/views/cms/view.rhtml
+++ b/app/views/cms/view.rhtml
@@ -5,9 +5,11 @@
<% button_bar(:style => 'margin-bottom: 1em;') do %>
<% parent_id = ((@article && @article.allow_children?) ? @article : nil) %>
- <% if !@article or !@article.blog? %>
+ <% if !@article or !@article.has_posts? %>
<%= button :newfolder, _('New folder'), :action => 'new', :type => 'Folder', :parent_id => parent_id %>
<%= button :newblog, _('New Blog'), :action => 'new', :type => 'Blog', :parent_id => parent_id %>
+ <%= button :newforum, _('New Forum'), :action => 'new', :type => 'Forum', :parent_id => parent_id %>
+ <%= button :newgallery, _('New Gallery'), :action => 'new', :type => 'Gallery', :parent_id => parent_id %>
<%= button('upload-file', _('Upload files'), :action => 'upload_files', :parent_id => parent_id) %>
<% end %>
<%= lightbox_button('new', label_for_new_article(@article), :action => 'new', :parent_id => parent_id) %>
diff --git a/app/views/content_viewer/forum_page.rhtml b/app/views/content_viewer/forum_page.rhtml
new file mode 100644
index 0000000..21938dd
--- /dev/null
+++ b/app/views/content_viewer/forum_page.rhtml
@@ -0,0 +1,11 @@
+<% add_rss_feed_to_head(@page.name, @page.feed.url) if @page.forum? && @page.feed %>
+
+
+
+ <%= @page.body %>
+
+
+
+
+ <%= (@posts.compact.empty? ? content_tag('em', _('(no posts)')) : list_forum_posts(@posts)) %>
+
diff --git a/app/views/content_viewer/view_page.rhtml b/app/views/content_viewer/view_page.rhtml
index 4706b5f..7b040b7 100644
--- a/app/views/content_viewer/view_page.rhtml
+++ b/app/views/content_viewer/view_page.rhtml
@@ -1,5 +1,5 @@
<%
- if @page.parent && @page.parent.blog? && @page.parent.feed
+ if @page.parent && @page.parent.has_posts? && @page.parent.feed
add_rss_feed_to_head(@page.parent.name, @page.parent.feed.url)
end
%>
@@ -15,7 +15,7 @@
profile.admin_url.merge({ :controller => 'cms', :action => 'edit', :id => @page.id }),
:class => 'button with-text icon-edit' %>
<% if !(profile.kind_of?(Enterprise) && environment.enabled?('disable_cms')) %>
- <% if @page != profile.home_page && !@page.blog? %>
+ <% if @page != profile.home_page && !@page.has_posts? %>
<%= link_to content_tag( 'span', _('Delete') ),
profile.admin_url.merge({ :controller => 'cms', :action => 'destroy', :id => @page }),
:class => 'button with-text icon-delete' %>
@@ -34,20 +34,20 @@
<% end %>
<% end %>
<% if !(profile.kind_of?(Enterprise) && environment.enabled?('disable_cms')) %>
- <% if !@page.display_as_gallery? %>
+ <% if !@page.gallery? %>
<%= 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)))) %>
<% end %>
- <% if (@page.folder? && !@page.blog?) || (@page.parent && @page.parent.folder? && !@page.parent.blog?) %>
+ <% if (@page.folder? && !@page.has_posts?) || (@page.parent && @page.parent.folder? && !@page.parent.has_posts?) %>
<%= button('upload-file', _('Upload files'), profile.admin_url.merge(:controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent))) %>
<% end %>
<% end %>
- <% if profile.kind_of?(Enterprise) && @page.display_as_gallery? %>
+ <% if profile.kind_of?(Enterprise) && @page.gallery? %>
<%= button('upload-file', _('Upload files'), :controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent)) %>
<% end %>
<% end %>
- <%= link_to(image_tag('icons-mime/rss-feed.png'), @page.feed.url, :class => 'blog-feed-link') if @page.blog? && @page.feed %>
+ <%= link_to(image_tag('icons-mime/rss-feed.png'), @page.feed.url, :class => 'blog-feed-link') if @page.has_posts? && @page.feed %>
<%= article_title(@page, :no_link => true) %>
diff --git a/config/initializers/dependencies.rb b/config/initializers/dependencies.rb
index 44cc43b..a4d869e 100644
--- a/config/initializers/dependencies.rb
+++ b/config/initializers/dependencies.rb
@@ -4,6 +4,7 @@ require 'acts_as_having_settings'
require 'acts_as_searchable'
require 'acts_as_having_boxes'
require 'acts_as_having_image'
+require 'acts_as_having_posts'
require 'route_if'
# third-party libraries
diff --git a/db/migrate/20101129234429_convert_folders_to_galleries.rb b/db/migrate/20101129234429_convert_folders_to_galleries.rb
new file mode 100644
index 0000000..9fef27a
--- /dev/null
+++ b/db/migrate/20101129234429_convert_folders_to_galleries.rb
@@ -0,0 +1,17 @@
+class ConvertFoldersToGalleries < ActiveRecord::Migration
+ def self.up
+ select_all("select id, setting from articles where type = 'Folder'").each do |folder|
+ view_as = YAML.load(folder['setting'])[:view_as]
+ update("update articles set type = 'Gallery' where id = %d" % folder['id']) if view_as == 'image_gallery'
+ end
+ end
+
+ def self.down
+ select_all("select id, setting from articles where type = 'Gallery'").each do |folder|
+ settings = YAML.load(folder['setting'])
+ settings[:view_as] = 'image_gallery'
+ assignments = ActiveRecord::Base.sanitize_sql_for_assignment(:setting => settings.to_yaml)
+ update("update articles set %s, type = 'Folder' where id = %d" % [assignments, folder['id']])
+ end
+ end
+end
diff --git a/features/forum.feature b/features/forum.feature
new file mode 100644
index 0000000..5645dee
--- /dev/null
+++ b/features/forum.feature
@@ -0,0 +1,63 @@
+Feature: forum
+ As a noosfero user
+ I want to have one or mutiple forums
+
+ Background:
+ Given I am on the homepage
+ And the following users
+ | login | name |
+ | joaosilva | Joao Silva |
+ And "joaosilva" has no articles
+ And I am logged in as "joaosilva"
+
+ Scenario: create a forum
+ Given I go to the Control panel
+ And I follow "Manage Content"
+ When I follow "New Forum"
+ And I fill in "Title" with "My Forum"
+ And I press "Save"
+ Then I should see "Configure forum"
+
+ Scenario: redirect to forum after create forum from cms
+ Given I go to the Control panel
+ And I follow "Manage Content"
+ When I follow "New Forum"
+ And I fill in "Title" with "Forum from cms"
+ And I press "Save"
+ Then I should be on /joaosilva/forum-from-cms
+
+ Scenario: create multiple forums
+ Given I go to the Control panel
+ And I follow "Manage Content"
+ And I follow "New Forum"
+ And I fill in "Title" with "Forum One"
+ And I press "Save"
+ Then I go to the Control panel
+ And I follow "Manage Content"
+ And I follow "New Forum"
+ And I fill in "Title" with "Forum Two"
+ And I press "Save"
+ Then I should not see "error"
+ And I should be on /joaosilva/forum-two
+
+ Scenario: cancel button back to cms
+ Given I go to the Control panel
+ And I follow "Manage Content"
+ And I follow "New Forum"
+ When I follow "Cancel" within ".main-block"
+ Then I should be on /myprofile/joaosilva/cms
+
+ Scenario: cancel button back to myprofile
+ Given I go to the Control panel
+ And I follow "Manage Content"
+ And I follow "New Forum"
+ When I follow "Cancel" within ".main-block"
+ Then I should be on /myprofile/joaosilva/cms
+
+ Scenario: configure forum when viewing it
+ Given the following forums
+ | owner | name |
+ | joaosilva | Forum One |
+ And I go to /joaosilva/forum-one
+ When I follow "Configure forum"
+ Then I should be on edit "Forum One" by joaosilva
diff --git a/features/gallery_navigation.feature b/features/gallery_navigation.feature
index 321ee2e..77a008e 100644
--- a/features/gallery_navigation.feature
+++ b/features/gallery_navigation.feature
@@ -6,9 +6,9 @@ Feature: gallery_navigation
Given the following users
| login |
| marciopunk |
- And the following folders
- | owner | name | view_as |
- | marciopunk | my-gallery | image_gallery |
+ And the following galleries
+ | owner | name |
+ | marciopunk | my-gallery |
And the following files
| owner | file | mime | parent |
| marciopunk | rails.png | image/png | my-gallery |
diff --git a/features/step_definitions/noosfero_steps.rb b/features/step_definitions/noosfero_steps.rb
index 53e7f98..b526136 100644
--- a/features/step_definitions/noosfero_steps.rb
+++ b/features/step_definitions/noosfero_steps.rb
@@ -41,12 +41,14 @@ Given /^the following blocks$/ do |table|
end
end
-Given /^the following (articles|events|blogs|folders)$/ do |content, table|
+Given /^the following (articles|events|blogs|folders|forums|galleries)$/ do |content, table|
klass = {
'articles' => TextileArticle,
'events' => Event,
'blogs' => Blog,
'folders' => Folder,
+ 'forums' => Forum,
+ 'galleries' => Gallery
}[content] || raise("Don't know how to build %s" % content)
table.hashes.map{|item| item.dup}.each do |item|
owner_identifier = item.delete("owner")
diff --git a/lib/acts_as_having_posts.rb b/lib/acts_as_having_posts.rb
new file mode 100644
index 0000000..1dff587
--- /dev/null
+++ b/lib/acts_as_having_posts.rb
@@ -0,0 +1,46 @@
+module ActsAsHavingPosts
+
+ module ClassMethods
+ def acts_as_having_posts(options = {})
+ has_many :posts, { :class_name => 'Article', :foreign_key => 'parent_id', :source => :children, :conditions => [ 'articles.type != ?', 'RssFeed' ], :order => 'published_at DESC, id DESC' }.merge(options)
+
+ attr_accessor :feed_attrs
+
+ after_create do |blog|
+ blog.children << RssFeed.new(:name => 'feed', :profile => blog.profile)
+ blog.feed = blog.feed_attrs
+ end
+
+ settings_items :posts_per_page, :type => :integer, :default => 5
+
+ self.send(:include, ActsAsHavingPosts)
+ end
+ end
+
+ def has_posts?
+ true
+ end
+
+ def feed
+ self.children.find(:first, :conditions => {:type => 'RssFeed'})
+ end
+
+ def feed=(attrs)
+ if attrs
+ if self.feed
+ self.feed.update_attributes(attrs)
+ else
+ self.feed_attrs = attrs
+ end
+ end
+ self.feed
+ end
+
+ def name=(value)
+ self.set_name(value)
+ self.slug = self.slug.blank? ? self.name.to_slug : self.slug.to_slug
+ end
+
+end
+
+ActiveRecord::Base.extend(ActsAsHavingPosts::ClassMethods)
diff --git a/public/designs/icons/tango/style.css b/public/designs/icons/tango/style.css
index 2993070..5b7379f 100644
--- a/public/designs/icons/tango/style.css
+++ b/public/designs/icons/tango/style.css
@@ -73,3 +73,5 @@
.icon-chat { background-image: url(Tango/16x16/apps/internet-group-chat.png); background-repeat: no-repeat }
.icon-scrap { background-image: url(Tango/16x16/actions/format-justify-left.png) }
.icon-reply { background-image: url(Tango/16x16/actions/mail-reply-sender.png) }
+.icon-newforum { background-image: url(Tango/16x16/apps/system-users.png) }
+.icon-newgallery { background-image: url(Tango/16x16/mimetypes/image-x-generic.png) }
diff --git a/public/designs/themes/base/style.css b/public/designs/themes/base/style.css
index 0ff110c..2cf9d78 100644
--- a/public/designs/themes/base/style.css
+++ b/public/designs/themes/base/style.css
@@ -1035,10 +1035,6 @@ hr.pre-posts, hr.sep-posts {
color: #AAA;
}
-#article-parent {
- display: none;
-}
-
.msie .post_comment_box {
padding-top: 15px;
}
diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css
index 9ecb6af..1c97a3d 100644
--- a/public/stylesheets/application.css
+++ b/public/stylesheets/application.css
@@ -5230,3 +5230,9 @@ h1#agenda-title {
float: none;
margin-top: 10px;
}
+
+/* Forum */
+
+.forum-posts .pagination {
+ margin-top: 20px;
+}
diff --git a/test/factories.rb b/test/factories.rb
index 33b9cd9..8ef87b2 100644
--- a/test/factories.rb
+++ b/test/factories.rb
@@ -409,4 +409,22 @@ module Noosfero::Factory
{ :login => username, :email => username + '@noosfero.colivre', :crypted_password => 'test'}.merge(params)
end
+ ###############################################
+ # Forum
+ ###############################################
+
+ def defaults_for_forum(params = {})
+ name = "forum_#{rand(1000)}"
+ { :profile_id => 1, :path => name, :name => name, :slug => name.to_slug }.merge(params)
+ end
+
+ ###############################################
+ # Gallery
+ ###############################################
+
+ def defaults_for_gallery(params = {})
+ name = "gallery_#{rand(1000)}"
+ { :profile_id => 1, :path => name, :name => name, :slug => name.to_slug }.merge(params)
+ end
+
end
diff --git a/test/functional/cms_controller_test.rb b/test/functional/cms_controller_test.rb
index 73e9883..7423824 100644
--- a/test/functional/cms_controller_test.rb
+++ b/test/functional/cms_controller_test.rb
@@ -802,6 +802,7 @@ class CmsControllerTest < Test::Unit::TestCase
should 'not offer to create special article types' do
get :new, :profile => profile.identifier
assert_no_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/new?type=Blog"}
+ assert_no_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/new?type=Forum"}
end
should 'offer to edit a blog' do
@@ -918,7 +919,7 @@ class CmsControllerTest < Test::Unit::TestCase
end
should 'create icon upload file in folder' do
- f = Folder.create!(:name => 'test_folder', :profile => profile, :view_as => 'image_gallery')
+ f = Gallery.create!(:name => 'test_folder', :profile => profile)
post :new, :profile => profile.identifier,
:type => UploadedFile.name,
:parent_id => f.id,
@@ -1155,6 +1156,8 @@ class CmsControllerTest < Test::Unit::TestCase
image = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg'))
image2 = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :created_at => 1.day.ago)
+ image2.updated_at = 1.day.ago
+ image2.send :update_without_callbacks
get :media_listing, :profile => profile.identifier
@@ -1296,4 +1299,115 @@ class CmsControllerTest < Test::Unit::TestCase
file_2.destroy
end
+ # Forum
+
+ should 'display posts per page input with default value on edit forum' do
+ n = Forum.new.posts_per_page.to_s
+ get :new, :profile => profile.identifier, :type => 'Forum'
+ assert_tag :tag => 'select', :attributes => { :name => 'article[posts_per_page]' }, :child => { :tag => 'option', :attributes => {:value => n, :selected => 'selected'} }
+ end
+
+ should 'offer to edit a forum' do
+ profile.articles << Forum.new(:name => 'forum test', :profile => profile)
+
+ profile.articles.reload
+ assert profile.has_forum?
+
+ b = profile.forum
+ get :index, :profile => profile.identifier
+ assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/edit/#{b.id}"}
+ end
+
+ should 'not offer to add folder to forum' do
+ profile.articles << Forum.new(:name => 'forum test', :profile => profile)
+
+ profile.articles.reload
+ assert profile.has_forum?
+
+ get :view, :profile => profile.identifier, :id => profile.forum.id
+ assert_no_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/new?parent_id=#{profile.forum.id}&type=Folder"}
+ end
+
+ should 'not show feed subitem for forum' do
+ profile.articles << Forum.new(:name => 'Forum for test', :profile => profile)
+
+ profile.articles.reload
+ assert profile.has_forum?
+
+ get :view, :profile => profile.identifier, :id => profile.forum.id
+
+ assert_no_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/edit/#{profile.forum.feed.id}" }
+ end
+
+ should 'update feed options by edit forum form' do
+ profile.articles << Forum.new(:name => 'Forum for test', :profile => profile)
+ post :edit, :profile => profile.identifier, :id => profile.forum.id, :article => { :feed => { :limit => 7 } }
+ assert_equal 7, profile.forum.feed.limit
+ end
+
+ should 'not offer folder to forum articles' do
+ @controller.stubs(:profile).returns(fast_create(Enterprise, :name => 'test_ent', :identifier => 'test_ent'))
+ forum = Forum.create!(:name => 'Forum for test', :profile => profile)
+ @controller.stubs(:params).returns({ :parent_id => forum.id })
+
+ assert_not_includes @controller.available_article_types, Folder
+ end
+
+ should 'not offer rssfeed to forum articles' do
+ @controller.stubs(:profile).returns(fast_create(Enterprise, :name => 'test_ent', :identifier => 'test_ent'))
+ forum = Forum.create!(:name => 'Forum for test', :profile => profile)
+ @controller.stubs(:params).returns({ :parent_id => forum.id })
+
+ assert_not_includes @controller.available_article_types, RssFeed
+ end
+
+ should 'update forum posts_per_page setting' do
+ profile.articles << Forum.new(:name => 'Forum for test', :profile => profile)
+ post :edit, :profile => profile.identifier, :id => profile.forum.id, :article => { :posts_per_page => 5 }
+ profile.forum.reload
+ assert_equal 5, profile.forum.posts_per_page
+ end
+
+ should "display 'New post' when create children of forum" do
+ a = Forum.create!(:name => 'forum_for_test', :profile => profile)
+ Article.stubs(:short_description).returns('bli')
+ get :view, :profile => profile.identifier, :id => a
+ assert_tag :tag => 'a', :content => 'New discussion topic'
+ end
+
+ should 'go to forum after create it' do
+ assert_difference Forum, :count do
+ post :new, :type => Forum.name, :profile => profile.identifier, :article => { :name => 'my-forum' }, :back_to => 'control_panel'
+ end
+ assert_redirected_to @profile.articles.find_by_name('my-forum').view_url
+ end
+
+ should 'back to forum after config forum' do
+ profile.articles << Forum.new(:name => 'my-forum', :profile => profile)
+ post :edit, :profile => profile.identifier, :id => profile.forum.id
+
+ assert_redirected_to @profile.articles.find_by_name('my-forum').view_url
+ end
+
+ should 'back to control panel if cancel create forum' do
+ get :new, :profile => profile.identifier, :type => Forum.name
+ assert_tag :tag => 'a', :content => 'Cancel', :attributes => { :href => /\/myprofile\/#{profile.identifier}/ }
+ end
+
+ should 'back to control panel if cancel config forum' do
+ profile.articles << Forum.new(:name => 'my-forum', :profile => profile)
+ get :edit, :profile => profile.identifier, :id => profile.forum.id
+ assert_tag :tag => 'a', :content => 'Cancel', :attributes => { :href => /\/myprofile\/#{profile.identifier}/ }
+ end
+
+ should 'not offer to upload files to forum' do
+ profile.articles << Forum.new(:name => 'forum test', :profile => profile)
+
+ profile.articles.reload
+ assert profile.has_forum?
+
+ get :view, :profile => profile.identifier, :id => profile.forum.id
+ assert_no_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/upload_files?parent_id=#{profile.forum.id}"}
+ end
+
end
diff --git a/test/functional/content_viewer_controller_test.rb b/test/functional/content_viewer_controller_test.rb
index 64f439c..36c0ef1 100644
--- a/test/functional/content_viewer_controller_test.rb
+++ b/test/functional/content_viewer_controller_test.rb
@@ -743,14 +743,14 @@ class ContentViewerControllerTest < Test::Unit::TestCase
should "display 'Upload files' when create children of image gallery" do
login_as(profile.identifier)
- f = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery')
+ f = Gallery.create!(:name => 'gallery', :profile => profile)
get :view_page, :profile => profile.identifier, :page => f.explode_path
assert_tag :tag => 'a', :content => 'Upload files', :attributes => {:href => /parent_id=#{f.id}/}
end
should "display 'New article' when showing folder child of image gallery" do
login_as(profile.identifier)
- folder1 = Folder.create!(:name => 'gallery1', :profile => profile, :view_as => 'image_gallery')
+ folder1 = Gallery.create!(:name => 'gallery1', :profile => profile)
folder1.children << folder2 = Folder.new(:name => 'gallery2', :profile => profile)
get :view_page, :profile => profile.identifier, :page => folder2.explode_path
@@ -759,7 +759,7 @@ class ContentViewerControllerTest < Test::Unit::TestCase
should "display 'Upload files' to image gallery when showing its children" do
login_as(profile.identifier)
- folder = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery')
+ folder = Gallery.create!(:name => 'gallery', :profile => profile)
file = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))
get :view_page, :profile => profile.identifier, :page => file.explode_path, :view => true
@@ -784,7 +784,7 @@ class ContentViewerControllerTest < Test::Unit::TestCase
should 'display all images from profile in the slideshow' do
@controller.stubs(:per_page).returns(1)
- folder = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery')
+ folder = Gallery.create!(:name => 'gallery', :profile => profile)
image1 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg'))
image2 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))
@@ -796,7 +796,7 @@ class ContentViewerControllerTest < Test::Unit::TestCase
should 'display default image in the slideshow if thumbnails were not processed' do
@controller.stubs(:per_page).returns(1)
- folder = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery')
+ folder = Gallery.create!(:name => 'gallery', :profile => profile)
image1 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg'))
@@ -807,7 +807,7 @@ class ContentViewerControllerTest < Test::Unit::TestCase
should 'display thumbnail image in the slideshow if thumbnails were processed' do
@controller.stubs(:per_page).returns(1)
- folder = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery')
+ folder = Gallery.create!(:name => 'gallery', :profile => profile)
image1 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg'))
@@ -819,7 +819,7 @@ class ContentViewerControllerTest < Test::Unit::TestCase
should 'display default image in gallery if thumbnails were not processed' do
@controller.stubs(:per_page).returns(1)
- folder = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery')
+ folder = Gallery.create!(:name => 'gallery', :profile => profile)
image1 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg'))
@@ -830,7 +830,7 @@ class ContentViewerControllerTest < Test::Unit::TestCase
should 'display thumbnail image in gallery if thumbnails were processed' do
@controller.stubs(:per_page).returns(1)
- folder = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery')
+ folder = Gallery.create!(:name => 'gallery', :profile => profile)
image1 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg'))
@@ -875,7 +875,7 @@ class ContentViewerControllerTest < Test::Unit::TestCase
should 'show only first 40 chars of abstract in image gallery' do
login_as(profile.identifier)
- folder = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery')
+ folder = Gallery.create!(:name => 'gallery', :profile => profile)
file = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))
file.abstract = 'a long abstract bigger then 40 chars for testing'
@@ -958,4 +958,141 @@ class ContentViewerControllerTest < Test::Unit::TestCase
assert_tag :tag => 'div', :attributes => { :class => /main-block/ }, :descendant => { :tag => 'a', :attributes => { :href => "/myprofile/testinguser/cms/edit/#{blog.id}" }, :content => 'Configure blog' }
end
+ # Forum
+
+ should 'list unpublished forum posts to owner with a different class' do
+ login_as('testinguser')
+ forum = Forum.create!(:name => 'A forum test', :profile => profile)
+ forum.posts << TextileArticle.create!(:name => 'Post', :profile => profile, :parent => forum, :published => false)
+
+ get :view_page, :profile => profile.identifier, :page => [forum.path]
+ assert_tag :tag => 'tr', :attributes => {:class => /not-published/}
+ end
+
+ should 'not list unpublished forum posts to a not logged person' do
+ forum = Forum.create!(:name => 'A forum test', :profile => profile)
+ forum.posts << TextileArticle.create!(:name => 'Post', :profile => profile, :parent => forum, :published => false)
+
+ get :view_page, :profile => profile.identifier, :page => [forum.path]
+ assert_no_tag :tag => 'a', :content => "Post"
+ end
+
+ should 'display pagination links of forum' do
+ forum = Forum.create!(:name => 'A forum test', :profile => profile, :posts_per_page => 5)
+ for n in 1..10
+ forum.posts << TextileArticle.create!(:name => "Post #{n}", :profile => profile, :parent => forum)
+ end
+ assert_equal 10, forum.posts.size
+
+ get :view_page, :profile => profile.identifier, :page => [forum.path]
+ assert_tag :tag => 'a', :attributes => { :href => "/#{profile.identifier}/#{forum.path}?npage=2", :rel => 'next' }
+ end
+
+ should 'display first page of forum posts' do
+ forum = Forum.create!(:name => 'My forum', :profile => profile, :posts_per_page => 5)
+ for n in 1..10
+ forum.children << art = TextileArticle.create!(:name => "Post #{n}", :profile => profile, :parent => forum)
+ art.updated_at = (10 - n).days.ago
+ art.send :update_without_callbacks
+ end
+ assert_equal 10, forum.posts.size
+
+ get :view_page, :profile => profile.identifier, :page => [forum.path]
+ for n in 1..5
+ assert_no_tag :tag => 'a', :content => "Post #{n}", :parent => { :tag => 'td', :parent => { :tag => 'tr', :attributes => { :class => /forum-post/ } } }
+ end
+ for n in 6..10
+ assert_tag :tag => 'a', :content => "Post #{n}", :parent => { :tag => 'td', :parent => { :tag => 'tr', :attributes => { :class => /forum-post/ } } }
+ end
+ end
+
+ should 'display others pages of forum posts' do
+ forum = Forum.create!(:name => 'My forum', :profile => profile, :posts_per_page => 5)
+ for n in 1..10
+ forum.children << art = TextileArticle.create!(:name => "Post #{n}", :profile => profile, :parent => forum)
+ art.updated_at = (10 - n).days.ago
+ art.send :update_without_callbacks
+ end
+ assert_equal 10, forum.posts.size
+
+ get :view_page, :profile => profile.identifier, :page => [forum.path], :npage => 2
+ for n in 1..5
+ assert_tag :tag => 'a', :content => "Post #{n}", :parent => { :tag => 'td', :parent => { :tag => 'tr', :attributes => { :class => /forum-post/ } } }
+ end
+ for n in 6..10
+ assert_no_tag :tag => 'a', :content => "Post #{n}", :parent => { :tag => 'td', :parent => { :tag => 'tr', :attributes => { :class => /forum-post/ } } }
+ end
+ end
+
+ should 'set year and month filter from URL params for forum' do
+ forum = Forum.create!(:name => "forum", :profile => profile)
+ profile.articles << forum
+
+ past_post = TextileArticle.create!(:name => "past post", :profile => profile, :parent => forum, :created_at => forum.created_at - 1.year)
+ actual_post = TextileArticle.create!(:name => "actual post", :profile => profile, :parent => forum)
+ forum.children << past_post
+ forum.children << actual_post
+
+ year, month = profile.forum.created_at.year.to_s, '%02d' % profile.forum.created_at.month
+
+ get :view_page, :profile => profile.identifier, :page => [profile.forum.path], :year => year, :month => month
+
+ assert_no_tag :tag => 'a', :content => past_post.title
+ assert_tag :tag => 'a', :content => actual_post.title
+ end
+
+ should "display 'New discussion topic' when create children of forum" do
+ login_as(profile.identifier)
+ a = Forum.create!(:name => 'article folder', :profile => profile)
+ Article.stubs(:short_description).returns('bli')
+ get :view_page, :profile => profile.identifier, :page => [a.path]
+ assert_tag :tag => 'a', :content => 'New discussion topic'
+ end
+
+ should "display same label for new article button of forum parent" do
+ login_as(profile.identifier)
+ a = Forum.create!(:name => 'article folder', :profile => profile)
+ Article.stubs(:short_description).returns('bli')
+ t = TextileArticle.create!(:name => 'first post', :parent => a, :profile => profile)
+ get :view_page, :profile => profile.identifier, :page => [t.path]
+ assert_tag :tag => 'a', :content => 'New discussion topic'
+ end
+
+ should 'add meta tag to rss feed on view forum' do
+ login_as(profile.identifier)
+ profile.articles << Forum.new(:name => 'Forum', :profile => profile)
+ get :view_page, :profile => profile.identifier, :page => ['forum']
+ assert_tag :tag => 'link', :attributes => { :rel => 'alternate', :type => 'application/rss+xml', :title => 'Forum', :href => "http://#{environment.default_hostname}/testinguser/forum/feed" }
+ end
+
+ should 'add meta tag to rss feed on view post forum' do
+ login_as(profile.identifier)
+ profile.articles << Forum.new(:name => 'Forum', :profile => profile)
+ profile.forum.posts << TextileArticle.new(:name => 'first post', :parent => profile.forum, :profile => profile)
+ get :view_page, :profile => profile.identifier, :page => ['forum', 'first-post']
+ assert_tag :tag => 'link', :attributes => { :rel => 'alternate', :type => 'application/rss+xml', :title => 'Forum', :href => "http://#{environment.default_hostname}/testinguser/forum/feed" }
+ end
+
+ should "not display 'Upload files' when viewing forum" do
+ login_as(profile.identifier)
+ b = Forum.create!(:name => 'article folder', :profile => profile)
+ get :view_page, :profile => profile.identifier, :page => b.explode_path
+ assert_no_tag :tag => 'a', :content => 'Upload files', :attributes => {:href => /parent_id=#{b.id}/}
+ end
+
+ should "not display 'Upload files' when viewing post from a forum" do
+ login_as(profile.identifier)
+ b = Forum.create!(:name => 'article folder', :profile => profile)
+ forum_post = TextileArticle.create!(:name => 'children-article', :profile => profile, :parent => b)
+ get :view_page, :profile => profile.identifier, :page => forum_post.explode_path
+ assert_no_tag :tag => 'a', :content => 'Upload files', :attributes => {:href => /parent_id=#{b.id}/}
+ end
+
+ should 'display link to edit forum for allowed' do
+ forum = fast_create(Forum, :profile_id => profile.id, :path => 'forum')
+ login_as(profile.identifier)
+ get :view_page, :profile => profile.identifier, :page => forum.explode_path
+ assert_tag :tag => 'div', :attributes => { :class => /main-block/ }, :descendant => { :tag => 'a', :attributes => { :href => "/myprofile/testinguser/cms/edit/#{forum.id}" }, :content => 'Configure forum' }
+ end
+
end
diff --git a/test/functional/profile_controller_test.rb b/test/functional/profile_controller_test.rb
index 411b2c1..4ef1861 100644
--- a/test/functional/profile_controller_test.rb
+++ b/test/functional/profile_controller_test.rb
@@ -459,7 +459,7 @@ class ProfileControllerTest < Test::Unit::TestCase
end
should 'show number of published images in index' do
- folder = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery')
+ folder = Gallery.create!(:name => 'gallery', :profile => profile)
published_file = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))
unpublished_file = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg'), :published => false)
diff --git a/test/unit/article_block_test.rb b/test/unit/article_block_test.rb
index 3ef840b..650e906 100644
--- a/test/unit/article_block_test.rb
+++ b/test/unit/article_block_test.rb
@@ -118,9 +118,7 @@ class ArticleBlockTest < Test::Unit::TestCase
should 'not display gallery pages navigation in content' do
profile = create_user('testuser').person
block = ArticleBlock.new
- gallery = fast_create(Folder, :profile_id => profile.id)
- gallery.view_as = 'image_gallery'
- gallery.save!
+ gallery = fast_create(Gallery, :profile_id => profile.id)
image = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => gallery)
block.article = image
block.save!
diff --git a/test/unit/article_test.rb b/test/unit/article_test.rb
index 7db23bf..187d999 100644
--- a/test/unit/article_test.rb
+++ b/test/unit/article_test.rb
@@ -1211,4 +1211,19 @@ class ArticleTest < Test::Unit::TestCase
assert_equal 31, (DateTime.parse('2010-07-06')).at_end_of_month.day
end
+ should 'not be a forum by default' do
+ assert !fast_create(Article).forum?
+ end
+
+ should 'not have posts by default' do
+ assert !fast_create(Article).has_posts?
+ end
+
+ should 'get article galleries' do
+ p = fast_create(Profile)
+ a = fast_create(Article, :profile_id => p.id)
+ g = fast_create(Gallery, :profile_id => p.id)
+ assert_equal [g], p.articles.galleries
+ end
+
end
diff --git a/test/unit/blog_test.rb b/test/unit/blog_test.rb
index 6f69311..49bfd6b 100644
--- a/test/unit/blog_test.rb
+++ b/test/unit/blog_test.rb
@@ -171,4 +171,8 @@ class BlogTest < ActiveSupport::TestCase
assert !blog.errors.invalid?(:visualization_format)
end
+ should 'have posts' do
+ assert Blog.new.has_posts?
+ end
+
end
diff --git a/test/unit/folder_test.rb b/test/unit/folder_test.rb
index c176161..113e697 100644
--- a/test/unit/folder_test.rb
+++ b/test/unit/folder_test.rb
@@ -28,31 +28,6 @@ class FolderTest < ActiveSupport::TestCase
assert_equal false, a.can_display_hits?
end
- should 'be viewed as image gallery' do
- p = create_user('test_user').person
- f = fast_create(Folder, :profile_id => p.id)
- f.view_as = 'image_gallery'; f.save!
- f.reload
-
- assert_equal 'image_gallery', f.view_as
- end
-
- should 'not allow view as bogus' do
- p = create_user('test_user').person
- f = fast_create(Folder, :profile_id => p.id)
- f.view_as = 'bogus'
- assert !f.save
- end
-
- should 'view as folder by default' do
- p = create_user('test_user').person
- f = fast_create(Folder, :profile_id => p.id)
- f.expects(:folder)
- f.to_html
-
- assert_equal 'folder', f.view_as
- end
-
should 'have images that are only images or other folders' do
p = create_user('test_user').person
f = fast_create(Folder, :profile_id => p.id)
diff --git a/test/unit/forum_helper_test.rb b/test/unit/forum_helper_test.rb
new file mode 100644
index 0000000..1906200
--- /dev/null
+++ b/test/unit/forum_helper_test.rb
@@ -0,0 +1,80 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class ForumHelperTest < Test::Unit::TestCase
+
+ include BlogHelper
+ include ForumHelper
+ include ContentViewerHelper
+ include ActionView::Helpers::AssetTagHelper
+ include ApplicationHelper
+
+ def setup
+ stubs(:show_date).returns('')
+ @environment = Environment.default
+ @profile = create_user('forum_helper_test').person
+ @forum = fast_create(Forum, :profile_id => profile.id, :name => 'Forum test')
+ end
+
+ attr :profile
+ attr :forum
+
+ def _(s); s; end
+ def h(s); s; end
+
+ should 'return a label for new children' do
+ assert_kind_of String, cms_label_for_new_children
+ end
+
+ should 'return a label for edit' do
+ assert_kind_of String, cms_label_for_edit
+ end
+
+ should 'list posts with different classes' do
+ forum.children << older_post = TextileArticle.create!(:name => 'First post', :profile => profile, :parent => forum, :published => false)
+ forum.children << newer_post = TextileArticle.create!(:name => 'Second post', :profile => profile, :parent => forum, :published => true)
+ older_post.updated_at = Time.now.ago(1.month); older_post.send(:update_without_callbacks)
+ assert_match /forum-post position-1 first odd-post.*forum-post position-2 last not-published even-post/, list_forum_posts(forum.posts)
+ end
+
+ should 'return post update if it has no comments' do
+ author = create_user('forum test author').person
+ some_post = TextileArticle.create!(:name => 'First post', :profile => profile, :parent => forum, :published => true)
+ some_post.expects(:author).returns(author)
+ assert some_post.comments.empty?
+ assert_equal "#{some_post.updated_at.to_s} ago by #{author.name}", last_topic_update(some_post)
+ end
+
+ should 'return last comment date if it has comments' do
+ some_post = TextileArticle.create!(:name => 'First post', :profile => profile, :parent => forum, :published => true)
+ a1, a2 = create_user('a1').person, create_user('a2').person
+ some_post.comments << Comment.new(:title => 'test', :body => 'test', :author => a1)
+ some_post.comments << Comment.new(:title => 'test', :body => 'test', :author => a2)
+ c = Comment.last
+ assert_equal 2, some_post.comments.count
+ assert_equal "#{c.created_at.to_s} ago by #{a2.name}", last_topic_update(some_post)
+ end
+
+ protected
+
+ def will_paginate(arg1, arg2)
+ end
+
+ def link_to(content, url)
+ content
+ end
+
+ def tag(tag, args = {})
+ attrs = args.map{|k,v| "#{k}='#{v}'"}.join(' ')
+ "<#{tag} #{attrs} />"
+ end
+
+ def content_tag(tag, content, options = {})
+ tag_attr = options.blank? ? "" : options.collect{ |o| "#{o[0]}=\"#{o[1]}\"" }.join(' ')
+ "<#{tag}#{tag_attr}>#{content}#{tag}>"
+ end
+
+ def time_ago_as_sentence(t = Time.now)
+ t.to_s
+ end
+
+end
diff --git a/test/unit/forum_test.rb b/test/unit/forum_test.rb
new file mode 100644
index 0000000..507ceb5
--- /dev/null
+++ b/test/unit/forum_test.rb
@@ -0,0 +1,103 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class ForumTest < ActiveSupport::TestCase
+
+ should 'be an article' do
+ assert_kind_of Article, Forum.new
+ end
+
+ should 'provide proper description' do
+ assert_kind_of String, Forum.description
+ end
+
+ should 'provide own icon name' do
+ assert_not_equal Article.new.icon_name, Forum.new.icon_name
+ end
+
+ should 'identify as folder' do
+ assert Forum.new.folder?, 'forum must identity itself as folder'
+ end
+
+ should 'identify as forum' do
+ assert Forum.new.forum?, 'forum must identity itself as forum'
+ end
+
+ should 'create rss feed automatically' do
+ p = create_user('testuser').person
+ b = create(Forum, :profile_id => p.id, :name => 'forum_feed_test')
+ assert_kind_of RssFeed, b.feed
+ end
+
+ should 'save feed options' do
+ p = create_user('testuser').person
+ p.articles << Forum.new(:profile => p, :name => 'forum_feed_test')
+ p.forum.feed = { :limit => 7 }
+ assert_equal 7, p.forum.feed.limit
+ end
+
+ should 'save feed options after create forum' do
+ p = create_user('testuser').person
+ p.articles << Forum.new(:profile => p, :name => 'forum_feed_test', :feed => { :limit => 7 })
+ assert_equal 7, p.forum.feed.limit
+ end
+
+ should 'list 5 posts per page by default' do
+ forum = Forum.new
+ assert_equal 5, forum.posts_per_page
+ end
+
+ should 'update posts per page setting' do
+ p = create_user('testuser').person
+ p.articles << Forum.new(:profile => p, :name => 'Forum test')
+ forum = p.forum
+ forum.posts_per_page = 7
+ assert forum.save!
+ assert_equal 7, p.forum.posts_per_page
+ end
+
+ should 'has posts' do
+ p = create_user('testuser').person
+ forum = fast_create(Forum, :profile_id => p.id, :name => 'Forum test')
+ post = fast_create(TextileArticle, :name => 'First post', :profile_id => p.id, :parent_id => forum.id)
+ forum.children << post
+ assert_includes forum.posts, post
+ end
+
+ should 'not includes rss feed in posts' do
+ p = create_user('testuser').person
+ forum = create(Forum, :profile_id => p.id, :name => 'Forum test')
+ assert_includes forum.children, forum.feed
+ assert_not_includes forum.posts, forum.feed
+ end
+
+ should 'list posts ordered by updated at' do
+ p = create_user('testuser').person
+ forum = fast_create(Forum, :profile_id => p.id, :name => 'Forum test')
+ newer = create(TextileArticle, :name => 'Post 2', :parent => forum, :profile => p)
+ older = create(TextileArticle, :name => 'Post 1', :parent => forum, :profile => p)
+ older.updated_at = Time.now - 1.month
+ older.send :update_without_callbacks
+ assert_equal [newer, older], forum.posts
+ end
+
+ should 'profile has more then one forum' do
+ p = create_user('testuser').person
+ fast_create(Forum, :name => 'Forum test', :profile_id => p.id)
+ assert_nothing_raised ActiveRecord::RecordInvalid do
+ Forum.create!(:name => 'Another Forum', :profile => p)
+ end
+ end
+
+ should 'not update slug from name for existing forum' do
+ p = create_user('testuser').person
+ forum = Forum.create!(:name => 'Forum test', :profile => p)
+ assert_equal 'forum-test', forum.slug
+ forum.name = 'Changed name'
+ assert_not_equal 'changed-name', forum.slug
+ end
+
+ should 'have posts' do
+ assert Forum.new.has_posts?
+ end
+
+end
diff --git a/test/unit/gallery_test.rb b/test/unit/gallery_test.rb
new file mode 100644
index 0000000..ac8b53e
--- /dev/null
+++ b/test/unit/gallery_test.rb
@@ -0,0 +1,138 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class GalleryTest < ActiveSupport::TestCase
+
+ should 'be an article' do
+ assert_kind_of Article, Gallery.new
+ end
+
+ should 'provide proper description' do
+ assert_kind_of String, Gallery.description
+ end
+
+ should 'provide proper short description' do
+ assert_kind_of String, Gallery.short_description
+ end
+
+ should 'provide own icon name' do
+ assert_not_equal Article.new.icon_name, Gallery.new.icon_name
+ end
+
+ should 'identify as folder' do
+ assert Folder.new.folder?, 'gallery must identity itself as folder'
+ end
+
+ should 'identify as gallery' do
+ assert Gallery.new.gallery?, 'gallery must identity itself as gallery'
+ end
+
+ should 'can display hits' do
+ profile = create_user('testuser').person
+ a = fast_create(Gallery, :profile_id => profile.id)
+ assert_equal false, a.can_display_hits?
+ end
+
+ should 'have images that are only images or other galleries' do
+ p = create_user('test_user').person
+ f = fast_create(Gallery, :profile_id => p.id)
+ file = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'), :parent => f, :profile => p)
+ image = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => f, :profile => p)
+ gallery = fast_create(Gallery, :profile_id => p.id, :parent_id => f.id)
+
+ assert_equivalent [gallery, image], f.images
+ end
+
+ should 'bring galleries first in alpha order in images listing' do
+ p = create_user('test_user').person
+ f = fast_create(Gallery, :profile_id => p.id)
+ gallery1 = fast_create(Gallery, :name => 'b', :profile_id => p.id, :parent_id => f.id)
+ image = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => f, :profile => p)
+ gallery2 = fast_create(Gallery, :name => 'c', :profile_id => p.id, :parent_id => f.id)
+ gallery3 = fast_create(Gallery, :name => 'a', :profile_id => p.id, :parent_id => f.id)
+
+ assert_equal [gallery3.id, gallery1.id, gallery2.id, image.id], f.images.map(&:id)
+ end
+
+ should 'images support pagination' do
+ p = create_user('test_user').person
+ f = fast_create(Gallery, :profile_id => p.id)
+ gallery = fast_create(Gallery, :profile_id => p.id, :parent_id => f.id)
+ image = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => f, :profile => p)
+
+ assert_equal [image], f.images.paginate(:page => 2, :per_page => 1)
+ end
+
+ should 'return newest text articles as news' do
+ c = fast_create(Community)
+ gallery = fast_create(Gallery, :profile_id => c.id)
+ f = fast_create(Gallery, :name => 'gallery', :profile_id => c.id, :parent_id => gallery.id)
+ u = UploadedFile.create!(:profile => c, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => gallery)
+ older_t = fast_create(TinyMceArticle, :name => 'old news', :profile_id => c.id, :parent_id => gallery.id)
+ t = fast_create(TinyMceArticle, :name => 'news', :profile_id => c.id, :parent_id => gallery.id)
+ t_in_f = fast_create(TinyMceArticle, :name => 'news', :profile_id => c.id, :parent_id => f.id)
+
+ assert_equal [t], gallery.news(1)
+ end
+
+ should 'not return highlighted news when not asked' do
+ c = fast_create(Community)
+ gallery = fast_create(Gallery, :profile_id => c.id)
+ highlighted_t = fast_create(TinyMceArticle, :name => 'high news', :profile_id => c.id, :highlighted => true, :parent_id => gallery.id)
+ t = fast_create(TinyMceArticle, :name => 'news', :profile_id => c.id, :parent_id => gallery.id)
+
+ assert_equal [t].map(&:slug), gallery.news(2).map(&:slug)
+ end
+
+ should 'return highlighted news when asked' do
+ c = fast_create(Community)
+ gallery = fast_create(Gallery, :profile_id => c.id)
+ highlighted_t = fast_create(TinyMceArticle, :name => 'high news', :profile_id => c.id, :highlighted => true, :parent_id => gallery.id)
+ t = fast_create(TinyMceArticle, :name => 'news', :profile_id => c.id, :parent_id => gallery.id)
+
+ assert_equal [highlighted_t].map(&:slug), gallery.news(2, true).map(&:slug)
+ end
+
+ should 'return published images as images' do
+ p = create_user('test_user').person
+ i = UploadedFile.create!(:profile => p, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))
+
+ c = fast_create(Community)
+ gallery = fast_create(Gallery, :profile_id => c.id)
+ pi = PublishedArticle.create!(:profile => c, :reference_article => i, :parent => gallery)
+
+ assert_includes gallery.images(true), pi
+ end
+
+ should 'not let pass javascript in the body' do
+ gallery = Gallery.new
+ gallery.body = ""
+ gallery.valid?
+
+ assert_no_match /(