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}" + 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 /(