mirror of
https://github.com/TracksApp/tracks.git
synced 2026-02-03 06:21:49 +01:00
The projects controller gets more RESTy. It now supports XML, RSS, ATOM, HTML and plain text views of the projects list.
Changes include: * Add assert_xml_select method for testing RSS and ATOM results (Thanks, Jamis! http://weblog.jamisbuck.org/2007/1/4/assert_xml_select) * Add resource_feeder plugin for generating RSS and ATOM feeds * Update the URL on the Feeds page to use /projects.rss or /projects.txt instead of FeedController link * Add created_at and updated_at timestamps to project table to support ATOM feeds * Added new filter to login_system "login_or_feed_token_required" to allow RSS, ATOM or text requests with token-based authentication Notes: * This will break previous project listing feed subscriptions. * RSS, ATOM & text feeds are available via session or HTTP_BASIC authentication, or by passing the user's token on the url; HTML and XML results are only available via session or HTTP_BASIC authentication git-svn-id: http://www.rousette.org.uk/svn/tracks-repos/trunk@415 a4c988fc-2ded-0310-b66e-134b36920a42
This commit is contained in:
parent
fda7788237
commit
d9d5ff4d06
35 changed files with 735 additions and 94 deletions
|
|
@ -62,6 +62,26 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
end
|
||||
|
||||
# Returns a count of next actions in the given context or project
|
||||
# The result is count and a string descriptor, correctly pluralised if there are no
|
||||
# actions or multiple actions
|
||||
#
|
||||
def count_undone_todos(todos_parent, string="actions")
|
||||
if (todos_parent.is_a?(Project) && todos_parent.hidden?)
|
||||
count = eval "@project_project_hidden_todo_counts[#{todos_parent.id}]"
|
||||
else
|
||||
count = eval "@#{todos_parent.class.to_s.downcase}_not_done_counts[#{todos_parent.id}]"
|
||||
end
|
||||
count = 0 if count == nil
|
||||
#count = todos_parent.todos.select{|t| !t.done }.size
|
||||
if count == 1
|
||||
word = string.singularize
|
||||
else
|
||||
word = string.pluralize
|
||||
end
|
||||
return count.to_s + " " + word
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def admin_login_required
|
||||
|
|
@ -101,7 +121,7 @@ class ApplicationController < ActionController::Base
|
|||
parents.each do |parent|
|
||||
eval("@#{parent}_project_hidden_todo_counts = Todo.count(:conditions => ['user_id = ? and state = ?', @user.id, 'project_hidden'], :group => :#{parent}_id)")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Set the contents of the flash message from a controller
|
||||
# Usage: notify :warning, "This is the message"
|
||||
|
|
|
|||
|
|
@ -45,14 +45,6 @@ class FeedController < ApplicationController
|
|||
end
|
||||
headers["Content-Type"] = "text/calendar"
|
||||
end
|
||||
|
||||
def list_projects_only
|
||||
init_not_done_counts('project')
|
||||
init_project_hidden_todo_counts
|
||||
@projects = @user.projects
|
||||
@description = "Lists all the projects for #{@user.login}."
|
||||
render :action => 'projects_' + params['feedtype']
|
||||
end
|
||||
|
||||
def list_contexts_only
|
||||
init_not_done_counts('context')
|
||||
|
|
|
|||
|
|
@ -1,14 +1,31 @@
|
|||
class ProjectsController < ApplicationController
|
||||
|
||||
helper :todos, :notes
|
||||
helper :application, :todos, :notes
|
||||
before_filter :init, :except => [:create, :destroy, :order]
|
||||
skip_before_filter :login_required, :only => [:index]
|
||||
prepend_before_filter :login_or_feed_token_required, :only => [:index]
|
||||
session :off, :only => :index, :if => Proc.new { |req| ['rss','atom','txt'].include?(req.parameters[:format]) }
|
||||
|
||||
def index
|
||||
init_project_hidden_todo_counts
|
||||
@page_title = "TRACKS::List Projects"
|
||||
respond_to do |wants|
|
||||
wants.html
|
||||
wants.xml { render :xml => @projects.to_xml( :except => :user_id ) }
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
init_project_hidden_todo_counts
|
||||
@page_title = "TRACKS::List Projects"
|
||||
render
|
||||
end
|
||||
format.xml { render :xml => @projects.to_xml( :except => :user_id ) }
|
||||
format.rss do
|
||||
render_rss_feed_for @projects, :feed => Project.feed_options(@user),
|
||||
:item => { :description => lambda { |p| p.summary(count_undone_todos(p)) } }
|
||||
end
|
||||
format.atom do
|
||||
render_atom_feed_for @projects, :feed => Project.feed_options(@user),
|
||||
:item => { :description => lambda { |p| p.summary(count_undone_todos(p)) },
|
||||
:author => lambda { |p| nil } }
|
||||
end
|
||||
format.text do
|
||||
render :action => 'index_text', :layout => false, :content_type => Mime::TEXT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ class UsersController < ApplicationController
|
|||
# GET /users
|
||||
# GET /users.xml
|
||||
def index
|
||||
@users = User.find(:all, :order => 'login')
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
@page_title = "TRACKS::Manage Users"
|
||||
|
|
@ -21,10 +22,7 @@ class UsersController < ApplicationController
|
|||
# we store the URL so that we get returned here when signup is successful
|
||||
store_location
|
||||
end
|
||||
format.xml do
|
||||
@users = User.find(:all)
|
||||
render :xml => @users.to_xml(:except => [ :password ])
|
||||
end
|
||||
format.xml { render :xml => @users.to_xml(:except => [ :password ]) }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -113,19 +113,7 @@ module ApplicationHelper
|
|||
# actions or multiple actions
|
||||
#
|
||||
def count_undone_todos(todos_parent, string="actions")
|
||||
if (todos_parent.is_a?(Project) && todos_parent.hidden?)
|
||||
count = eval "@project_project_hidden_todo_counts[#{todos_parent.id}]"
|
||||
else
|
||||
count = eval "@#{todos_parent.class.to_s.downcase}_not_done_counts[#{todos_parent.id}]"
|
||||
end
|
||||
count = 0 if count == nil
|
||||
#count = todos_parent.todos.select{|t| !t.done }.size
|
||||
if count == 1
|
||||
word = string.singularize
|
||||
else
|
||||
word = string.pluralize
|
||||
end
|
||||
return count.to_s + " " + word
|
||||
@controller.count_undone_todos(todos_parent, string)
|
||||
end
|
||||
|
||||
def link_to_context(context, descriptor = sanitize(context.name))
|
||||
|
|
|
|||
|
|
@ -31,20 +31,6 @@ module FeedHelper
|
|||
return result_string
|
||||
end
|
||||
|
||||
def build_projects_text_page(projects)
|
||||
result_string = ""
|
||||
projects.each do |p|
|
||||
result_string << "\n" + p.name.upcase + "\n"
|
||||
|
||||
result_string << p.description + "\n" if p.description_present?
|
||||
result_string << "#{count_undone_todos(p)}. Project is #{p.state}.\n"
|
||||
result_string << "#{p.linkurl}\n" if p.linkurl_present?
|
||||
result_string << "\n"
|
||||
end
|
||||
|
||||
return result_string
|
||||
end
|
||||
|
||||
def build_contexts_text_page(contexts)
|
||||
result_string = ""
|
||||
contexts.each do |c|
|
||||
|
|
|
|||
|
|
@ -6,12 +6,26 @@ module FeedlistHelper
|
|||
linkoptions.merge!(options)
|
||||
link_to(image_tag, linkoptions, :title => "RSS feed")
|
||||
end
|
||||
|
||||
def rss_formatted_link(options = {})
|
||||
image_tag = image_tag("feed-icon.png", :size => "16X16", :border => 0, :class => "rss-icon")
|
||||
linkoptions = { :token => @user.word, :format => 'rss' }
|
||||
linkoptions.merge!(options)
|
||||
link_to(image_tag, linkoptions, :title => "RSS feed")
|
||||
end
|
||||
|
||||
def text_feed_link(options = {})
|
||||
linkoptions = {:controller => 'feed', :action => 'text', :login => "#{@user.login}", :token => "#{@user.word}"}
|
||||
linkoptions.merge!(options)
|
||||
link_to('<span class="feed">TXT</span>', linkoptions, :title => "Plain text feed" )
|
||||
end
|
||||
|
||||
def text_formatted_link(options = {})
|
||||
linkoptions = { :token => @user.word, :format => 'txt' }
|
||||
linkoptions.merge!(options)
|
||||
link_to('<span class="feed">TXT</span>', linkoptions, :title => "Plain text feed" )
|
||||
end
|
||||
|
||||
|
||||
def ical_feed_link(options = {})
|
||||
linkoptions = {:controller => 'feed', :action => 'ical', :login => "#{@user.login}", :token => "#{@user.word}"}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,13 @@ class Project < ActiveRecord::Base
|
|||
NullProject.new
|
||||
end
|
||||
|
||||
def self.feed_options(user)
|
||||
{
|
||||
:title => 'Tracks Projects',
|
||||
:description => "Lists all the projects for #{user.display_name}."
|
||||
}
|
||||
end
|
||||
|
||||
def to_param
|
||||
url_friendly_name
|
||||
end
|
||||
|
|
@ -48,6 +55,20 @@ class Project < ActiveRecord::Base
|
|||
def linkurl_present?
|
||||
attribute_present?("linkurl")
|
||||
end
|
||||
|
||||
def title
|
||||
name
|
||||
end
|
||||
|
||||
def summary(undone_todo_count)
|
||||
project_description = ''
|
||||
project_description += sanitize(markdown( description )) if description_present?
|
||||
project_description += "<p>#{undone_todo_count}. "
|
||||
project_description += "Project is #{state}. "
|
||||
project_description += "<a href=\"#{linkurl}\">#{linkurl}</a>" if linkurl_present?
|
||||
project_description += "</p>"
|
||||
project_description
|
||||
end
|
||||
|
||||
def hide_todos
|
||||
todos.each do |t|
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ class User < ActiveRecord::Base
|
|||
:order => 'position ASC',
|
||||
:dependent => :delete_all
|
||||
has_many :todos,
|
||||
:order => 'completed_at DESC, created_at DESC',
|
||||
:order => 'completed_at DESC, todos.created_at DESC',
|
||||
:dependent => :delete_all
|
||||
has_many :deferred_todos,
|
||||
:class_name => 'Todo',
|
||||
:conditions => [ 'state = ?', 'deferred' ],
|
||||
:order => 'show_from ASC, created_at DESC' do
|
||||
:order => 'show_from ASC, todos.created_at DESC' do
|
||||
def find_and_activate_ready
|
||||
find(:all, :conditions => ['show_from <= ?', Time.now.utc.to_date ]).collect { |t| t.activate_and_save! }
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
@headers["Content-Type"] = "text/xml; charset=utf-8"
|
||||
xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
|
||||
xml.channel do
|
||||
xml.title(@title)
|
||||
xml.link(projects_url)
|
||||
xml.description(@description)
|
||||
@projects.each do |p|
|
||||
xml.item do
|
||||
xml.title(p.name)
|
||||
xml.link(project_url(p))
|
||||
project_description = ''
|
||||
project_description += sanitize(markdown( p.description )) if p.description_present?
|
||||
project_description += "<p>#{count_undone_todos(p)}. "
|
||||
project_description += "Project is #{p.state}. "
|
||||
project_description += "<a href=\"#{p.linkurl}\">#{p.linkurl}</a>" if p.linkurl_present?
|
||||
project_description += "</p>"
|
||||
xml.description(project_description)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
<% @headers["Content-Type"] = "text/plain; charset=utf-8" -%>
|
||||
<%= build_projects_text_page( @projects ) -%>
|
||||
|
|
@ -45,8 +45,8 @@
|
|||
All Contexts
|
||||
</li>
|
||||
<li>
|
||||
<%= rss_feed_link({ :action => 'list_projects_only', :feedtype => 'rss' }) %>
|
||||
<%= text_feed_link({ :action => 'list_projects_only', :feedtype => 'text' }) %>
|
||||
<%= rss_formatted_link({:controller => 'projects', :action => 'index'}) %>
|
||||
<%= text_formatted_link({:controller => 'projects', :action => 'index'}) %>
|
||||
All Projects
|
||||
</li>
|
||||
<li><h4>Feeds for uncompleted actions in a specific context:</h4>
|
||||
|
|
|
|||
7
tracks/app/views/projects/index_text.rhtml
Normal file
7
tracks/app/views/projects/index_text.rhtml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<% @projects.each do |p| -%>
|
||||
|
||||
<%= p.name.upcase %>
|
||||
<%= p.description + "\n" if p.description_present? -%>
|
||||
<%= count_undone_todos(p)%>. Project is <%= p.state %>.
|
||||
<%= p.linkurl + "\n" if p.linkurl_present? -%>
|
||||
<% end -%>
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
<% end -%>
|
||||
|
||||
<% if item.completed? -%>
|
||||
(<%= item.context.name %><%= ", " + item.project.name if item.project_id %>)
|
||||
(<%= item.context.name %><%= ", " + item.project.name unless item.project.nil? %>)
|
||||
<% else -%>
|
||||
<% if (parent_container_type == "project" || parent_container_type == "tickler") -%>
|
||||
<%= item_link_to_context( item ) %>
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ ActionController::Routing::Routes.draw do |map|
|
|||
# Projects Routes
|
||||
map.resources :projects, :collection => {:order => :post}
|
||||
map.connect 'project/:project/feed/:action/:login/:token', :controller => 'feed'
|
||||
map.connect 'projects/feed/:feedtype/:login/:token', :controller => 'feed', :action => 'list_projects_only'
|
||||
|
||||
# Notes Routes
|
||||
map.resources :notes
|
||||
|
|
|
|||
12
tracks/db/migrate/026_add_project_timestamps.rb
Normal file
12
tracks/db/migrate/026_add_project_timestamps.rb
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
class AddProjectTimestamps < ActiveRecord::Migration
|
||||
def self.up
|
||||
add_column :projects, :created_at, :timestamp
|
||||
add_column :projects, :updated_at, :timestamp
|
||||
end
|
||||
|
||||
|
||||
def self.down
|
||||
remove_column :projects, :created_at
|
||||
remove_column :projects, :updated_at
|
||||
end
|
||||
end
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
# migrations feature of ActiveRecord to incrementally modify your database, and
|
||||
# then regenerate this schema definition.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 25) do
|
||||
ActiveRecord::Schema.define(:version => 26) do
|
||||
|
||||
create_table "contexts", :force => true do |t|
|
||||
t.column "name", :string, :default => "", :null => false
|
||||
|
|
@ -60,11 +60,13 @@ ActiveRecord::Schema.define(:version => 25) do
|
|||
add_index "preferences", ["user_id"], :name => "index_preferences_on_user_id"
|
||||
|
||||
create_table "projects", :force => true do |t|
|
||||
t.column "name", :string, :default => "", :null => false
|
||||
t.column "position", :integer, :default => 0, :null => false
|
||||
t.column "user_id", :integer, :default => 0, :null => false
|
||||
t.column "name", :string, :default => "", :null => false
|
||||
t.column "position", :integer, :default => 0, :null => false
|
||||
t.column "user_id", :integer, :default => 0, :null => false
|
||||
t.column "description", :text
|
||||
t.column "state", :string, :limit => 20, :default => "active", :null => false
|
||||
t.column "state", :string, :limit => 20, :default => "active", :null => false
|
||||
t.column "created_at", :datetime
|
||||
t.column "updated_at", :datetime
|
||||
end
|
||||
|
||||
add_index "projects", ["user_id"], :name => "index_projects_on_user_id"
|
||||
|
|
|
|||
|
|
@ -30,6 +30,16 @@ module LoginSystem
|
|||
def protect?(action)
|
||||
true
|
||||
end
|
||||
|
||||
def login_or_feed_token_required
|
||||
if ['rss', 'atom', 'txt'].include?(params[:format])
|
||||
if user = User.find_by_word(params[:token])
|
||||
set_current_user(user)
|
||||
return true
|
||||
end
|
||||
end
|
||||
login_required
|
||||
end
|
||||
|
||||
# login_required filter. add
|
||||
#
|
||||
|
|
@ -53,7 +63,7 @@ module LoginSystem
|
|||
http_user, http_pass = get_basic_auth_data
|
||||
if user = User.authenticate(http_user, http_pass)
|
||||
session['user_id'] = user.id
|
||||
get_current_user
|
||||
set_current_user(user)
|
||||
return true
|
||||
end
|
||||
|
||||
|
|
@ -75,7 +85,7 @@ module LoginSystem
|
|||
http_user, http_pass = get_basic_auth_data
|
||||
if user = User.authenticate(http_user, http_pass)
|
||||
session['user_id'] = user.id
|
||||
get_current_user
|
||||
set_current_user(user)
|
||||
return true
|
||||
end
|
||||
|
||||
|
|
@ -89,6 +99,12 @@ module LoginSystem
|
|||
@prefs = @user.prefs unless @user.nil?
|
||||
@user
|
||||
end
|
||||
|
||||
def set_current_user(user)
|
||||
@user = user
|
||||
@prefs = @user.prefs unless @user.nil?
|
||||
@user
|
||||
end
|
||||
|
||||
# overwrite if you want to have special behavior in case the user is not authorized
|
||||
# to access the current operation.
|
||||
|
|
@ -96,10 +112,13 @@ module LoginSystem
|
|||
# example use :
|
||||
# a popup window might just close itself for instance
|
||||
def access_denied
|
||||
respond_to do |wants|
|
||||
wants.html { redirect_to :controller=>"login", :action =>"login" }
|
||||
wants.js { render :partial => 'login/redirect_to_login' }
|
||||
wants.xml { basic_auth_denied }
|
||||
respond_to do |format|
|
||||
format.html { redirect_to :controller=>"login", :action =>"login" }
|
||||
format.js { render :partial => 'login/redirect_to_login' }
|
||||
format.xml { basic_auth_denied }
|
||||
format.rss { basic_auth_denied }
|
||||
format.atom { basic_auth_denied }
|
||||
format.text { basic_auth_denied }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
13
tracks/test/fixtures/projects.yml
vendored
13
tracks/test/fixtures/projects.yml
vendored
|
|
@ -1,4 +1,11 @@
|
|||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
<%
|
||||
|
||||
def today
|
||||
Time.now.utc.to_s(:db)
|
||||
end
|
||||
|
||||
%>
|
||||
|
||||
timemachine:
|
||||
id: 1
|
||||
|
|
@ -7,6 +14,8 @@ timemachine:
|
|||
position: 1
|
||||
state: 'active'
|
||||
user_id: 1
|
||||
created_at: <%= today %>
|
||||
updated_at: <%= today %>
|
||||
|
||||
moremoney:
|
||||
id: 2
|
||||
|
|
@ -15,6 +24,8 @@ moremoney:
|
|||
position: 2
|
||||
state: 'active'
|
||||
user_id: 1
|
||||
created_at: <%= today %>
|
||||
updated_at: <%= today %>
|
||||
|
||||
gardenclean:
|
||||
id: 3
|
||||
|
|
@ -23,3 +34,5 @@ gardenclean:
|
|||
position: 3
|
||||
state: 'active'
|
||||
user_id: 1
|
||||
created_at: <%= today %>
|
||||
updated_at: <%= today %>
|
||||
|
|
|
|||
30
tracks/test/functional/feedlist_controller_test.rb
Normal file
30
tracks/test/functional/feedlist_controller_test.rb
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
require 'feedlist_controller'
|
||||
|
||||
# Re-raise errors caught by the controller.
|
||||
class FeedlistController; def rescue_action(e) raise e end; end
|
||||
|
||||
class FeedlistControllerTest < Test::Unit::TestCase
|
||||
fixtures :users, :preferences, :projects, :contexts, :todos, :notes
|
||||
|
||||
def setup
|
||||
assert_equal "test", ENV['RAILS_ENV']
|
||||
assert_equal "change-me", Tracks::Config.salt
|
||||
@controller = FeedlistController.new
|
||||
@request = ActionController::TestRequest.new
|
||||
@response = ActionController::TestResponse.new
|
||||
end
|
||||
|
||||
def test_get_index_when_not_logged_in
|
||||
get :index
|
||||
assert_redirected_to :controller => 'login', :action => 'login'
|
||||
end
|
||||
|
||||
def test_get_index_by_logged_in_user
|
||||
@request.session['user_id'] = users(:other_user).id
|
||||
get :index
|
||||
assert_response :success
|
||||
assert_equal "TRACKS::Feeds", assigns['page_title']
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -6,7 +6,7 @@ require 'projects_controller'
|
|||
class ProjectsController; def rescue_action(e) raise e end; end
|
||||
|
||||
class ProjectsControllerTest < TodoContainerControllerTestBase
|
||||
fixtures :users, :todos, :preferences, :projects
|
||||
fixtures :users, :todos, :preferences, :projects, :contexts
|
||||
|
||||
def setup
|
||||
perform_setup(Project, ProjectsController)
|
||||
|
|
@ -78,5 +78,106 @@ class ProjectsControllerTest < TodoContainerControllerTestBase
|
|||
assert p.reload().active?
|
||||
end
|
||||
|
||||
def test_rss_feed_content
|
||||
@request.session['user_id'] = users(:admin_user).id
|
||||
get :index, { :format => "rss" }
|
||||
assert_equal 'application/rss+xml; charset=utf-8', @response.headers["Content-Type"]
|
||||
#puts @response.body
|
||||
|
||||
assert_xml_select 'rss[version="2.0"]' do
|
||||
assert_xml_select 'channel' do
|
||||
assert_xml_select '>title', 'Tracks Projects'
|
||||
assert_xml_select '>description', "Lists all the projects for #{users(:admin_user).display_name}."
|
||||
assert_xml_select 'language', 'en-us'
|
||||
assert_xml_select 'ttl', '40'
|
||||
end
|
||||
assert_xml_select 'item', 3 do
|
||||
assert_xml_select 'title', /.+/
|
||||
assert_xml_select 'description', /<p>\d+ actions. Project is (active|hidden|completed). <\/p>/
|
||||
%w(guid link).each do |node|
|
||||
assert_xml_select node, /http:\/\/test.host\/projects\/.+/
|
||||
end
|
||||
assert_xml_select 'pubDate', projects(:timemachine).created_at.to_s(:rfc822)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_rss_feed_not_accessible_to_anonymous_user_without_token
|
||||
@request.session['user_id'] = nil
|
||||
get :index, { :format => "rss" }
|
||||
assert_response 401
|
||||
end
|
||||
|
||||
def test_rss_feed_not_accessible_to_anonymous_user_with_invalid_token
|
||||
@request.session['user_id'] = nil
|
||||
get :index, { :format => "rss", :token => 'foo' }
|
||||
assert_response 401
|
||||
end
|
||||
|
||||
def test_rss_feed_accessible_to_anonymous_user_with_valid_token
|
||||
@request.session['user_id'] = nil
|
||||
get :index, { :format => "rss", :token => users(:admin_user).word }
|
||||
assert_response :ok
|
||||
end
|
||||
|
||||
def test_atom_feed_content
|
||||
@request.session['user_id'] = users(:admin_user).id
|
||||
get :index, { :format => "atom" }
|
||||
assert_equal 'application/atom+xml; charset=utf-8', @response.headers["Content-Type"]
|
||||
#puts @response.body
|
||||
|
||||
assert_xml_select 'feed[xmlns="http://www.w3.org/2005/Atom"]' do
|
||||
assert_xml_select '>title', 'Tracks Projects'
|
||||
assert_xml_select '>subtitle', "Lists all the projects for #{users(:admin_user).display_name}."
|
||||
assert_xml_select 'entry', 3 do
|
||||
assert_xml_select 'title', /.+/
|
||||
assert_xml_select 'content[type="html"]', /<p>\d+ actions. Project is (active|hidden|completed). <\/p>/
|
||||
assert_xml_select 'published', projects(:timemachine).created_at.to_s(:rfc822)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_atom_feed_not_accessible_to_anonymous_user_without_token
|
||||
@request.session['user_id'] = nil
|
||||
get :index, { :format => "atom" }
|
||||
assert_response 401
|
||||
end
|
||||
|
||||
def test_atom_feed_not_accessible_to_anonymous_user_with_invalid_token
|
||||
@request.session['user_id'] = nil
|
||||
get :index, { :format => "atom", :token => 'foo' }
|
||||
assert_response 401
|
||||
end
|
||||
|
||||
def test_atom_feed_accessible_to_anonymous_user_with_valid_token
|
||||
@request.session['user_id'] = nil
|
||||
get :index, { :format => "atom", :token => users(:admin_user).word }
|
||||
assert_response :ok
|
||||
end
|
||||
|
||||
def test_text_feed_content
|
||||
@request.session['user_id'] = users(:admin_user).id
|
||||
get :index, { :format => "txt" }
|
||||
assert_equal 'text/plain; charset=utf-8', @response.headers["Content-Type"]
|
||||
#puts @response.body
|
||||
end
|
||||
|
||||
def test_text_feed_not_accessible_to_anonymous_user_without_token
|
||||
@request.session['user_id'] = nil
|
||||
get :index, { :format => "txt" }
|
||||
assert_response 401
|
||||
end
|
||||
|
||||
def test_text_feed_not_accessible_to_anonymous_user_with_invalid_token
|
||||
@request.session['user_id'] = nil
|
||||
get :index, { :format => "txt", :token => 'foo' }
|
||||
assert_response 401
|
||||
end
|
||||
|
||||
def test_text_feed_accessible_to_anonymous_user_with_valid_token
|
||||
@request.session['user_id'] = nil
|
||||
get :index, { :format => "txt", :token => users(:admin_user).word }
|
||||
assert_response :ok
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -80,17 +80,17 @@ class FeedSmokeTest < ActionController::IntegrationTest
|
|||
end
|
||||
|
||||
def test_all_projects_rss
|
||||
assert_success "/projects/feed/rss/admin/#{ users(:admin_user).word }"
|
||||
assert_success "/projects.rss?token=#{ users(:admin_user).word }"
|
||||
end
|
||||
|
||||
def test_all_projects_txt
|
||||
assert_success "/projects/feed/text/admin/#{ users(:admin_user).word }"
|
||||
assert_success "/projects.txt?token=#{ users(:admin_user).word }"
|
||||
end
|
||||
|
||||
def test_all_projects_txt_with_hidden_project
|
||||
p = projects(:timemachine)
|
||||
p.hide!
|
||||
assert_success "/projects/feed/text/admin/#{ users(:admin_user).word }"
|
||||
assert_success "/projects.txt?token=#{ users(:admin_user).word }"
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ require 'projects_controller'
|
|||
# Re-raise errors caught by the controller.
|
||||
class ProjectsController; def rescue_action(e) raise e end; end
|
||||
|
||||
class ProjectsControllerXmlApiTest < ActionController::IntegrationTest
|
||||
class ProjectXmlApiTest < ActionController::IntegrationTest
|
||||
fixtures :users, :projects
|
||||
|
||||
@@project_name = "My New Project"
|
||||
|
|
@ -51,7 +51,15 @@ class ProjectsControllerXmlApiTest < ActionController::IntegrationTest
|
|||
def test_creates_new_project
|
||||
initial_count = Project.count
|
||||
authenticated_post_xml_to_project_create
|
||||
assert_response_and_body_matches 200, %r|^<\?xml version="1\.0" encoding="UTF-8"\?>\n<project>\n <description></description>\n <id type=\"integer\">[0-9]+</id>\n <name>#{@@project_name}</name>\n <position type=\"integer\">1</position>\n <state>active</state>\n</project>$|
|
||||
assert_response :success
|
||||
assert_xml_select 'project' do
|
||||
assert_xml_select "description"
|
||||
assert_xml_select 'id[type="integer"]', /[0-9]+/
|
||||
assert_xml_select 'name', @@project_name
|
||||
assert_xml_select 'position[type="integer"]', 1
|
||||
assert_xml_select 'state', 'active'
|
||||
end
|
||||
#assert_response_and_body_matches 200, %r|^<\?xml version="1\.0" encoding="UTF-8"\?>\n<project>\n <description></description>\n <id type=\"integer\">[0-9]+</id>\n <name>#{@@project_name}</name>\n <position type=\"integer\">1</position>\n <state>active</state>\n</project>$|
|
||||
assert_equal initial_count + 1, Project.count
|
||||
project1 = Project.find_by_name(@@project_name)
|
||||
assert_not_nil project1, "expected project '#{@@project_name}' to be created"
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@ class UsersXmlApiTest < ActionController::IntegrationTest
|
|||
|
||||
def test_get_users_as_xml
|
||||
get '/users.xml', {}, basic_auth_headers()
|
||||
#puts @response.body
|
||||
assert_response :success
|
||||
assert_tag :tag => "users",
|
||||
:children => { :count => 3, :only => { :tag => "user" } }
|
||||
|
|
@ -85,7 +84,6 @@ class UsersXmlApiTest < ActionController::IntegrationTest
|
|||
|
||||
def test_get_user_as_xml
|
||||
get "/users/#{users(:other_user).login}.xml", {}, basic_auth_headers()
|
||||
puts @response.body
|
||||
assert_response :success
|
||||
assert_tag :tag => "user"
|
||||
assert_no_tag :tag => "password"
|
||||
|
|
|
|||
|
|
@ -30,6 +30,16 @@ class Test::Unit::TestCase
|
|||
end
|
||||
return string
|
||||
end
|
||||
|
||||
def xml_document
|
||||
@xml_document ||= HTML::Document.new(@response.body, false, true)
|
||||
end
|
||||
|
||||
def assert_xml_select(*args)
|
||||
@html_document = xml_document
|
||||
assert_select(*args)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class ActionController::IntegrationTest
|
||||
|
|
|
|||
|
|
@ -143,4 +143,8 @@ class ProjectTest < Test::Unit::TestCase
|
|||
assert_equal 'Build_a_working_time_machine', @timemachine.to_param
|
||||
end
|
||||
|
||||
def test_title_reader_returns_name
|
||||
assert_equal @timemachine.name, @timemachine.title
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
7
tracks/vendor/plugins/resource_feeder/README
vendored
Normal file
7
tracks/vendor/plugins/resource_feeder/README
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
ResourceFeeder
|
||||
==============
|
||||
|
||||
Simple feeds for resources
|
||||
|
||||
NOTE: This plugin depends on the latest version of simply_helpful, available here:
|
||||
http://dev.rubyonrails.org/svn/rails/plugins/simply_helpful/
|
||||
22
tracks/vendor/plugins/resource_feeder/Rakefile
vendored
Normal file
22
tracks/vendor/plugins/resource_feeder/Rakefile
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
require 'rake'
|
||||
require 'rake/testtask'
|
||||
require 'rake/rdoctask'
|
||||
|
||||
desc 'Default: run unit tests.'
|
||||
task :default => :test
|
||||
|
||||
desc 'Test the resource_feed plugin.'
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.libs << 'lib'
|
||||
t.pattern = 'test/**/*_test.rb'
|
||||
t.verbose = true
|
||||
end
|
||||
|
||||
desc 'Generate documentation for the resource_feed plugin.'
|
||||
Rake::RDocTask.new(:rdoc) do |rdoc|
|
||||
rdoc.rdoc_dir = 'rdoc'
|
||||
rdoc.title = 'ResourceFeed'
|
||||
rdoc.options << '--line-numbers' << '--inline-source'
|
||||
rdoc.rdoc_files.include('README')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
end
|
||||
2
tracks/vendor/plugins/resource_feeder/init.rb
vendored
Normal file
2
tracks/vendor/plugins/resource_feeder/init.rb
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
require 'resource_feeder'
|
||||
ActionController::Base.send(:include, ResourceFeeder::Rss, ResourceFeeder::Atom)
|
||||
2
tracks/vendor/plugins/resource_feeder/lib/resource_feeder.rb
vendored
Normal file
2
tracks/vendor/plugins/resource_feeder/lib/resource_feeder.rb
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
require 'resource_feeder/rss'
|
||||
require 'resource_feeder/atom'
|
||||
78
tracks/vendor/plugins/resource_feeder/lib/resource_feeder/atom.rb
vendored
Normal file
78
tracks/vendor/plugins/resource_feeder/lib/resource_feeder/atom.rb
vendored
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
module ResourceFeeder
|
||||
module Atom
|
||||
extend self
|
||||
|
||||
def render_atom_feed_for(resources, options = {})
|
||||
render :text => atom_feed_for(resources, options), :content_type => Mime::ATOM
|
||||
end
|
||||
|
||||
def atom_feed_for(resources, options = {})
|
||||
xml = Builder::XmlMarkup.new(:indent => 2)
|
||||
|
||||
options[:feed] ||= {}
|
||||
options[:item] ||= {}
|
||||
options[:url_writer] ||= self
|
||||
|
||||
if options[:class] || resources.first
|
||||
klass = options[:class] || resources.first.class
|
||||
new_record = klass.new
|
||||
else
|
||||
options[:feed] = { :title => "Empty", :link => "http://example.com" }
|
||||
end
|
||||
|
||||
options[:feed][:title] ||= klass.name.pluralize
|
||||
options[:feed][:id] ||= "tag:#{request.host_with_port}:#{klass.name.pluralize}"
|
||||
options[:feed][:link] ||= SimplyHelpful::RecordIdentifier.polymorphic_url(new_record, options[:url_writer])
|
||||
|
||||
options[:item][:title] ||= [ :title, :subject, :headline, :name ]
|
||||
options[:item][:description] ||= [ :description, :body, :content ]
|
||||
options[:item][:pub_date] ||= [ :updated_at, :updated_on, :created_at, :created_on ]
|
||||
options[:item][:author] ||= [ :author, :creator ]
|
||||
|
||||
resource_link = lambda { |r| SimplyHelpful::RecordIdentifier.polymorphic_url(r, options[:url_writer]) }
|
||||
|
||||
xml.instruct!
|
||||
xml.feed "xml:lang" => "en-US", "xmlns" => 'http://www.w3.org/2005/Atom' do
|
||||
xml.title(options[:feed][:title])
|
||||
xml.id(options[:feed][:id])
|
||||
xml.link(:rel => 'alternate', :type => 'text/html', :href => options[:feed][:link])
|
||||
xml.link(:rel => 'self', :type => 'application/atom+xml', :href => options[:feed][:self]) if options[:feed][:self]
|
||||
xml.subtitle(options[:feed][:description]) if options[:feed][:description]
|
||||
|
||||
for resource in resources
|
||||
published_at = call_or_read(options[:item][:pub_date], resource)
|
||||
|
||||
xml.entry do
|
||||
xml.title(call_or_read(options[:item][:title], resource))
|
||||
xml.content(call_or_read(options[:item][:description], resource), :type => 'html')
|
||||
xml.id("tag:#{request.host_with_port},#{published_at.xmlschema}:#{call_or_read(options[:item][:guid] || options[:item][:link] || resource_link, resource)}")
|
||||
xml.published(published_at.xmlschema)
|
||||
xml.updated((resource.respond_to?(:updated_at) ? call_or_read(options[:item][:pub_date] || :updated_at, resource) : published_at).xmlschema)
|
||||
xml.link(:rel => 'alternate', :type => 'text/html', :href => call_or_read(options[:item][:link] || options[:item][:guid] || resource_link, resource))
|
||||
|
||||
if author = call_or_read(options[:item][:author], resource)
|
||||
xml.author do
|
||||
xml.name()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def call_or_read(procedure_or_attributes, resource)
|
||||
case procedure_or_attributes
|
||||
when Array
|
||||
attributes = procedure_or_attributes
|
||||
resource.send(attributes.select { |a| resource.respond_to?(a) }.first)
|
||||
when Symbol
|
||||
attribute = procedure_or_attributes
|
||||
resource.send(attribute)
|
||||
when Proc
|
||||
procedure = procedure_or_attributes
|
||||
procedure.call(resource)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
79
tracks/vendor/plugins/resource_feeder/lib/resource_feeder/rss.rb
vendored
Normal file
79
tracks/vendor/plugins/resource_feeder/lib/resource_feeder/rss.rb
vendored
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
module ResourceFeeder
|
||||
module Rss
|
||||
extend self
|
||||
|
||||
def render_rss_feed_for(resources, options = {})
|
||||
render :text => rss_feed_for(resources, options), :content_type => Mime::RSS
|
||||
end
|
||||
|
||||
def rss_feed_for(resources, options = {})
|
||||
xml = Builder::XmlMarkup.new(:indent => 2)
|
||||
|
||||
options[:feed] ||= {}
|
||||
options[:item] ||= {}
|
||||
options[:url_writer] ||= self
|
||||
|
||||
if options[:class] || resources.first
|
||||
klass = options[:class] || resources.first.class
|
||||
new_record = klass.new
|
||||
else
|
||||
options[:feed] = { :title => "Empty", :link => "http://example.com" }
|
||||
end
|
||||
use_content_encoded = options[:item].has_key?(:content_encoded)
|
||||
|
||||
options[:feed][:title] ||= klass.name.pluralize
|
||||
options[:feed][:link] ||= SimplyHelpful::RecordIdentifier.polymorphic_url(new_record, options[:url_writer])
|
||||
options[:feed][:language] ||= "en-us"
|
||||
options[:feed][:ttl] ||= "40"
|
||||
|
||||
options[:item][:title] ||= [ :title, :subject, :headline, :name ]
|
||||
options[:item][:description] ||= [ :description, :body, :content ]
|
||||
options[:item][:pub_date] ||= [ :updated_at, :updated_on, :created_at, :created_on ]
|
||||
|
||||
resource_link = lambda { |r| SimplyHelpful::RecordIdentifier.polymorphic_url(r, options[:url_writer]) }
|
||||
|
||||
rss_root_attributes = { :version => 2.0 }
|
||||
rss_root_attributes.merge!("xmlns:content" => "http://purl.org/rss/1.0/modules/content/") if use_content_encoded
|
||||
|
||||
xml.instruct!
|
||||
|
||||
xml.rss(rss_root_attributes) do
|
||||
xml.channel do
|
||||
xml.title(options[:feed][:title])
|
||||
xml.link(options[:feed][:link])
|
||||
xml.description(options[:feed][:description]) if options[:feed][:description]
|
||||
xml.language(options[:feed][:language])
|
||||
xml.ttl(options[:feed][:ttl])
|
||||
|
||||
for resource in resources
|
||||
xml.item do
|
||||
xml.title(call_or_read(options[:item][:title], resource))
|
||||
xml.description(call_or_read(options[:item][:description], resource))
|
||||
if use_content_encoded then
|
||||
xml.content(:encoded) { xml.cdata!(call_or_read(options[:item][:content_encoded], resource)) }
|
||||
end
|
||||
xml.pubDate(call_or_read(options[:item][:pub_date], resource).to_s(:rfc822))
|
||||
xml.guid(call_or_read(options[:item][:guid] || options[:item][:link] || resource_link, resource))
|
||||
xml.link(call_or_read(options[:item][:link] || options[:item][:guid] || resource_link, resource))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def call_or_read(procedure_or_attributes, resource)
|
||||
case procedure_or_attributes
|
||||
when Array
|
||||
attributes = procedure_or_attributes
|
||||
resource.send(attributes.select { |a| resource.respond_to?(a) }.first)
|
||||
when Symbol
|
||||
attribute = procedure_or_attributes
|
||||
resource.send(attribute)
|
||||
when Proc
|
||||
procedure = procedure_or_attributes
|
||||
procedure.call(resource)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
85
tracks/vendor/plugins/resource_feeder/test/atom_feed_test.rb
vendored
Normal file
85
tracks/vendor/plugins/resource_feeder/test/atom_feed_test.rb
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
require File.dirname(__FILE__) + '/test_helper'
|
||||
class AtomFeedTest < Test::Unit::TestCase
|
||||
attr_reader :request
|
||||
|
||||
def setup
|
||||
@request = OpenStruct.new
|
||||
@request.host_with_port = 'example.com'
|
||||
@records = Array.new(5).fill(Post.new)
|
||||
@records.each &:save
|
||||
end
|
||||
|
||||
def test_default_atom_feed
|
||||
atom_feed_for @records
|
||||
|
||||
assert_select 'feed' do
|
||||
assert_select '>title', 'Posts'
|
||||
assert_select '>id', "tag:#{request.host_with_port}:Posts"
|
||||
assert_select '>link' do
|
||||
assert_select "[rel='alternate']"
|
||||
assert_select "[type='text/html']"
|
||||
assert_select "[href='http://example.com/posts']"
|
||||
end
|
||||
assert_select 'entry', 5 do
|
||||
assert_select 'title', :text => 'feed title (title)'
|
||||
assert_select "content[type='html']", '<p>feed description (description)</p>'
|
||||
assert_select 'id', "tag:#{request.host_with_port},#{@records.first.created_at.xmlschema}:#{'http://example.com/posts/1'}"
|
||||
assert_select 'published', @records.first.created_at.xmlschema
|
||||
assert_select 'updated', @records.first.created_at.xmlschema
|
||||
assert_select 'link' do
|
||||
assert_select "[rel='alternate']"
|
||||
assert_select "[type='text/html']"
|
||||
assert_select "[href='http://example.com/posts/1']"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_allow_custom_feed_options
|
||||
atom_feed_for @records, :feed => { :title => 'Custom Posts', :link => '/posts', :description => 'stuff', :self => '/posts.atom' }
|
||||
|
||||
assert_select 'feed>title', 'Custom Posts'
|
||||
assert_select "feed>link[href='/posts']"
|
||||
assert_select 'feed>subtitle', 'stuff'
|
||||
assert_select 'feed>link' do
|
||||
assert_select "[rel='self']"
|
||||
assert_select "[type='application/atom+xml']"
|
||||
assert_select "[href='/posts.atom']"
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_allow_custom_item_attributes
|
||||
atom_feed_for @records, :item => { :title => :name, :description => :body, :pub_date => :create_date, :link => :id }
|
||||
|
||||
assert_select 'entry', 5 do
|
||||
assert_select 'title', :text => 'feed title (name)'
|
||||
assert_select "content[type='html']", '<p>feed description (body)</p>'
|
||||
assert_select 'published', (@records.first.created_at - 5.minutes).xmlschema
|
||||
assert_select 'updated', (@records.first.created_at - 5.minutes).xmlschema
|
||||
assert_select 'id', "tag:#{request.host_with_port},#{(@records.first.created_at - 5.minutes).xmlschema}:1"
|
||||
assert_select 'link' do
|
||||
assert_select "[rel='alternate']"
|
||||
assert_select "[type='text/html']"
|
||||
assert_select "[href='1']"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_allow_custom_item_attribute_blocks
|
||||
atom_feed_for @records, :item => { :title => lambda { |r| r.name }, :description => lambda { |r| r.body }, :pub_date => lambda { |r| r.create_date },
|
||||
:link => lambda { |r| "/#{r.created_at.to_i}" }, :guid => lambda { |r| r.created_at.to_i } }
|
||||
|
||||
assert_select 'entry', 5 do
|
||||
assert_select 'title', :text => 'feed title (name)'
|
||||
assert_select "content[type='html']", '<p>feed description (body)</p>'
|
||||
assert_select 'published', (@records.first.created_at - 5.minutes).xmlschema
|
||||
assert_select 'updated', (@records.first.created_at - 5.minutes).xmlschema
|
||||
assert_select 'id', /:\d+$/
|
||||
assert_select 'link' do
|
||||
assert_select "[rel='alternate']"
|
||||
assert_select "[type='text/html']"
|
||||
assert_select "[href=?]", /^\/\d+$/
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
86
tracks/vendor/plugins/resource_feeder/test/rss_feed_test.rb
vendored
Normal file
86
tracks/vendor/plugins/resource_feeder/test/rss_feed_test.rb
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
require File.dirname(__FILE__) + '/test_helper'
|
||||
class RssFeedTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@records = Array.new(5).fill(Post.new)
|
||||
@records.each &:save
|
||||
end
|
||||
|
||||
def test_default_rss_feed
|
||||
rss_feed_for @records
|
||||
|
||||
assert_select 'rss[version="2.0"]' do
|
||||
assert_select 'channel' do
|
||||
assert_select '>title', 'Posts'
|
||||
assert_select '>link', 'http://example.com/posts'
|
||||
assert_select 'language', 'en-us'
|
||||
assert_select 'ttl', '40'
|
||||
end
|
||||
assert_select 'item', 5 do
|
||||
assert_select 'title', :text => 'feed title (title)'
|
||||
assert_select 'description', '<p>feed description (description)</p>'
|
||||
%w(guid link).each do |node|
|
||||
assert_select node, 'http://example.com/posts/1'
|
||||
end
|
||||
assert_select 'pubDate', @records.first.created_at.to_s(:rfc822)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_allow_custom_feed_options
|
||||
rss_feed_for @records, :feed => { :title => 'Custom Posts', :link => '/posts', :description => 'stuff', :language => 'en-gb', :ttl => '80' }
|
||||
|
||||
assert_select 'channel>title', 'Custom Posts'
|
||||
assert_select 'channel>link', '/posts'
|
||||
assert_select 'channel>description', 'stuff'
|
||||
assert_select 'channel>language', 'en-gb'
|
||||
assert_select 'channel>ttl', '80'
|
||||
end
|
||||
|
||||
def test_should_allow_custom_item_attributes
|
||||
rss_feed_for @records, :item => { :title => :name, :description => :body, :pub_date => :create_date, :link => :id }
|
||||
|
||||
assert_select 'item', 5 do
|
||||
assert_select 'title', :text => 'feed title (name)'
|
||||
assert_select 'description', '<p>feed description (body)</p>'
|
||||
assert_select 'pubDate', (@records.first.created_at - 5.minutes).to_s(:rfc822)
|
||||
assert_select 'link', '1'
|
||||
assert_select 'guid', '1'
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_allow_custom_item_attribute_blocks
|
||||
rss_feed_for @records, :item => { :title => lambda { |r| r.name }, :description => lambda { |r| r.body }, :pub_date => lambda { |r| r.create_date },
|
||||
:link => lambda { |r| "/#{r.created_at.to_i}" }, :guid => lambda { |r| r.created_at.to_i } }
|
||||
|
||||
assert_select 'item', 5 do
|
||||
assert_select 'title', :text => 'feed title (name)'
|
||||
assert_select 'description', '<p>feed description (body)</p>'
|
||||
assert_select 'pubDate', (@records.first.created_at - 5.minutes).to_s(:rfc822)
|
||||
end
|
||||
end
|
||||
|
||||
# note that assert_select isnt easily able to get elements that have xml namespaces (as it thinks they are
|
||||
# invalid html psuedo children), so we do some manual testing with the response body
|
||||
def test_should_allow_content_encoded_for_items
|
||||
rss_feed_for @records, :item => { :content_encoded => :full_html_body }
|
||||
|
||||
html_content = "<strong>Here is some <i>full</i> content, with out any excerpts</strong>"
|
||||
assert_equal 5, @response.body.scan("<![CDATA[#{html_content}]]>").size
|
||||
assert_select 'item', 5 do
|
||||
assert_select 'description + *', "<![CDATA[#{html_content}" # assert_select seems to strip the ending cdata tag
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_have_content_encoded_namespace_if_used
|
||||
rss_feed_for @records, :item => { :content_encoded => :full_html_body }
|
||||
assert_equal %[<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">\n],
|
||||
@response.body.grep(/<rss version="2\.0.*"/).first
|
||||
end
|
||||
|
||||
def test_should_have_normal_rss_root_without_content_encoded
|
||||
rss_feed_for @records
|
||||
assert_equal %[<rss version="2.0">\n],
|
||||
@response.body.grep(/<rss version="2\.0.*"/).first
|
||||
end
|
||||
|
||||
end
|
||||
64
tracks/vendor/plugins/resource_feeder/test/test_helper.rb
vendored
Normal file
64
tracks/vendor/plugins/resource_feeder/test/test_helper.rb
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
RAILS_ENV = 'test'
|
||||
require File.expand_path(File.join(File.dirname(__FILE__), '../../../../config/environment.rb'))
|
||||
require 'action_controller/test_process'
|
||||
require 'breakpoint'
|
||||
require 'ostruct'
|
||||
|
||||
class Post
|
||||
attr_reader :id, :created_at
|
||||
def save; @id = 1; @created_at = Time.now.utc end
|
||||
def new_record?; @id.nil? end
|
||||
|
||||
[:title, :name].each do |attr_name|
|
||||
define_method attr_name do
|
||||
"feed title (#{attr_name})"
|
||||
end
|
||||
end
|
||||
|
||||
[:description, :body].each do |attr_name|
|
||||
define_method attr_name do
|
||||
"<p>feed description (#{attr_name})</p>"
|
||||
end
|
||||
end
|
||||
|
||||
def full_html_body
|
||||
"<strong>Here is some <i>full</i> content, with out any excerpts</strong>"
|
||||
end
|
||||
|
||||
def create_date
|
||||
@created_at - 5.minutes
|
||||
end
|
||||
end
|
||||
|
||||
class Test::Unit::TestCase
|
||||
include ResourceFeeder::Rss, ResourceFeeder::Atom
|
||||
|
||||
def render_feed(xml)
|
||||
@response = OpenStruct.new
|
||||
@response.headers = {'Content-Type' => 'text/xml'}
|
||||
@response.body = xml
|
||||
end
|
||||
|
||||
def rss_feed_for_with_ostruct(resources, options = {})
|
||||
render_feed rss_feed_for_without_ostruct(resources, options)
|
||||
end
|
||||
|
||||
def atom_feed_for_with_ostruct(resources, options = {})
|
||||
render_feed atom_feed_for_without_ostruct(resources, options)
|
||||
end
|
||||
|
||||
alias_method_chain :rss_feed_for, :ostruct
|
||||
alias_method_chain :atom_feed_for, :ostruct
|
||||
|
||||
def html_document
|
||||
@html_document ||= HTML::Document.new(@response.body, false, true)
|
||||
end
|
||||
|
||||
def posts_url
|
||||
"http://example.com/posts"
|
||||
end
|
||||
|
||||
def post_url(post)
|
||||
"http://example.com/posts/#{post.id}"
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue