mirror of
https://github.com/TracksApp/tracks.git
synced 2025-09-22 05:50:47 +02:00
Work in progress: has_many_polymorphs does not work with rails 3.2 because of intrusive changes in rails internals. I think we need to rip out this dependency...
This commit is contained in:
parent
a83c8b3f92
commit
86afd42148
162 changed files with 704 additions and 8724 deletions
62
Gemfile
62
Gemfile
|
@ -5,8 +5,31 @@ gem 'rails', '3.2.3'
|
|||
# Bundle edge Rails instead:
|
||||
# gem 'rails', :git => 'git://github.com/rails/rails.git'
|
||||
|
||||
gem 'sqlite3'
|
||||
# you may comment out the database driver you will not be using.
|
||||
# This will prevent a native build of the driver. Building native drivers is not always possible on all hosters
|
||||
gem "sqlite3"
|
||||
gem "mysql2"
|
||||
|
||||
gem "highline", "~>1.5.0"
|
||||
gem "RedCloth"
|
||||
# gem "sanitize", "~>1.2.1"
|
||||
# gem "will_paginate"
|
||||
gem "has_many_polymorphs", :git => "git://github.com/lrbalt/has_many_polymorphs.git", :branch => "try"
|
||||
gem "acts_as_list", "~>0.1.4"
|
||||
gem "aasm", "~>2.2.0"
|
||||
# TODO: gem "rubyjedi-actionwebservice", :require => "actionwebservice"
|
||||
# gem "rubycas-client", "~>2.2.1"
|
||||
# gem "ruby-openid", :require => "openid"
|
||||
# gem "open_id_authentication"
|
||||
# gem 'htmlentities', '~> 4.3.0'
|
||||
# gem "mail"
|
||||
# gem "swf_fu"
|
||||
|
||||
# if RUBY_VERSION.to_f >= 1.9
|
||||
# gem "soap4r-ruby1.9"
|
||||
# else
|
||||
# gem "soap4r", "~>1.5.8"
|
||||
# end
|
||||
|
||||
# Gems used only for assets and not required
|
||||
# in production environments by default.
|
||||
|
@ -23,7 +46,7 @@ end
|
|||
gem 'jquery-rails'
|
||||
|
||||
# To use ActiveModel has_secure_password
|
||||
# gem 'bcrypt-ruby', '~> 3.0.0'
|
||||
gem 'bcrypt-ruby', '~> 3.0.0'
|
||||
|
||||
# To use Jbuilder templates for JSON
|
||||
# gem 'jbuilder'
|
||||
|
@ -36,3 +59,38 @@ gem 'jquery-rails'
|
|||
|
||||
# To use debugger
|
||||
# gem 'ruby-debug19', :require => 'ruby-debug'
|
||||
|
||||
|
||||
# group :development do
|
||||
# if RUBY_VERSION.to_f >= 1.9
|
||||
# gem "ruby-debug19"
|
||||
# gem "mongrel", "1.2.0.pre2"
|
||||
# else
|
||||
# gem "ruby-debug"
|
||||
# gem "mongrel"
|
||||
# end
|
||||
# gem "yard"
|
||||
# end
|
||||
#
|
||||
# group :test do
|
||||
# gem "test-unit", "1.2.3"
|
||||
# gem "flexmock"
|
||||
# gem "ZenTest", ">=4.0.0"
|
||||
# gem "hpricot"
|
||||
# gem "hoe"
|
||||
# gem "rspec-rails", "~>1.3.3"
|
||||
# # TODO: gem "thoughtbot-factory_girl"
|
||||
# gem 'memory_test_fix', '~>0.1.3'
|
||||
# gem "capybara", ">=0.3.5"
|
||||
# gem "selenium-webdriver" # Note that > 2.14 has problems: https://code.google.com/p/selenium/issues/detail?id=3075
|
||||
# gem "database_cleaner", ">=0.5.0"
|
||||
# gem "cucumber-rails", "~>0.3.2"
|
||||
# gem "aruba", "0.2.2", :path => "vendor/gems/aruba-0.2.2"
|
||||
|
||||
# uncomment to use the webkit option. This depends on Qt to be installed
|
||||
#gem "capybara-webkit"
|
||||
|
||||
# uncomment to be able to make screenshots from scenarios
|
||||
#gem "capybara-screenshot"
|
||||
#gem "launchy"
|
||||
# end
|
||||
|
|
90
Gemfile.lock
90
Gemfile.lock
|
@ -1,6 +1,16 @@
|
|||
GIT
|
||||
remote: git://github.com/lrbalt/has_many_polymorphs.git
|
||||
revision: bb0a7af8ac7418717954cab42a5476ca9806f858
|
||||
branch: try
|
||||
specs:
|
||||
has_many_polymorphs (3.0.0.beta1)
|
||||
activerecord
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
RedCloth (4.2.9)
|
||||
aasm (2.2.1)
|
||||
actionmailer (3.2.3)
|
||||
actionpack (= 3.2.3)
|
||||
mail (~> 2.4.4)
|
||||
|
@ -28,56 +38,22 @@ GEM
|
|||
activesupport (3.2.3)
|
||||
i18n (~> 0.6)
|
||||
multi_json (~> 1.0)
|
||||
acts_as_list (0.1.5)
|
||||
arel (3.0.2)
|
||||
bcrypt-ruby (3.0.1)
|
||||
builder (3.0.0)
|
||||
<<<<<<< HEAD
|
||||
capybara (1.1.2)
|
||||
mime-types (>= 1.16)
|
||||
nokogiri (>= 1.3.3)
|
||||
rack (>= 1.0.0)
|
||||
rack-test (>= 0.5.4)
|
||||
selenium-webdriver (~> 2.0)
|
||||
xpath (~> 0.1.4)
|
||||
cgi_multipart_eof_fix (2.5.0)
|
||||
childprocess (0.3.1)
|
||||
ffi (~> 1.0.6)
|
||||
columnize (0.3.6)
|
||||
cucumber (1.1.4)
|
||||
builder (>= 2.1.2)
|
||||
diff-lcs (>= 1.1.2)
|
||||
gherkin (~> 2.7.1)
|
||||
json (>= 1.4.6)
|
||||
term-ansicolor (>= 1.0.6)
|
||||
cucumber-rails (0.3.2)
|
||||
cucumber (>= 0.8.0)
|
||||
daemons (1.1.8)
|
||||
database_cleaner (0.7.1)
|
||||
diff-lcs (1.1.3)
|
||||
fastthread (1.0.7)
|
||||
ffi (1.0.11)
|
||||
flexmock (0.9.0)
|
||||
gem_plugin (0.2.3)
|
||||
gherkin (2.7.7)
|
||||
json (>= 1.4.6)
|
||||
highline (1.5.2)
|
||||
hoe (2.13.1)
|
||||
rake (~> 0.8)
|
||||
hpricot (0.8.6)
|
||||
htmlentities (4.3.1)
|
||||
httpclient (2.2.4)
|
||||
=======
|
||||
coffee-rails (3.2.2)
|
||||
coffee-script (>= 2.2.0)
|
||||
railties (~> 3.2.0)
|
||||
coffee-script (2.2.0)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.2.0)
|
||||
coffee-script-source (1.3.1)
|
||||
erubis (2.7.0)
|
||||
execjs (1.3.0)
|
||||
multi_json (~> 1.0)
|
||||
highline (1.5.2)
|
||||
hike (1.2.1)
|
||||
>>>>>>> initial upgrade to rails 3.2.3
|
||||
i18n (0.6.0)
|
||||
journey (1.0.3)
|
||||
jquery-rails (2.0.2)
|
||||
|
@ -90,6 +66,7 @@ GEM
|
|||
treetop (~> 1.4.8)
|
||||
mime-types (1.18)
|
||||
multi_json (1.2.0)
|
||||
mysql2 (0.3.11)
|
||||
polyglot (0.3.3)
|
||||
rack (1.4.1)
|
||||
rack-cache (1.2)
|
||||
|
@ -131,7 +108,7 @@ GEM
|
|||
treetop (1.4.10)
|
||||
polyglot
|
||||
polyglot (>= 0.3.1)
|
||||
tzinfo (0.3.32)
|
||||
tzinfo (0.3.33)
|
||||
uglifier (1.2.4)
|
||||
execjs (>= 0.3.0)
|
||||
multi_json (>= 1.0.2)
|
||||
|
@ -140,41 +117,16 @@ PLATFORMS
|
|||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
<<<<<<< HEAD
|
||||
RedCloth (= 4.2.8)
|
||||
ZenTest (>= 4.0.0)
|
||||
RedCloth
|
||||
aasm (~> 2.2.0)
|
||||
acts_as_list (~> 0.1.4)
|
||||
aruba (= 0.2.2)!
|
||||
bcrypt-ruby (~> 2.1.4)
|
||||
capybara (>= 0.3.5)
|
||||
cucumber-rails (~> 0.3.2)
|
||||
database_cleaner (>= 0.5.0)
|
||||
flexmock
|
||||
highline (~> 1.5.0)
|
||||
hoe
|
||||
hpricot
|
||||
htmlentities (~> 4.3.0)
|
||||
mail
|
||||
memory_test_fix (~> 0.1.3)
|
||||
mongrel
|
||||
mysql
|
||||
rack (= 1.1.0)
|
||||
rails (~> 2.3.12)
|
||||
rake (~> 0.8.7)
|
||||
rspec-rails (~> 1.3.3)
|
||||
ruby-debug
|
||||
ruby-openid
|
||||
rubycas-client (~> 2.2.1)
|
||||
rubyjedi-actionwebservice
|
||||
sanitize (~> 1.2.1)
|
||||
selenium-webdriver
|
||||
soap4r (~> 1.5.8)
|
||||
=======
|
||||
bcrypt-ruby (~> 3.0.0)
|
||||
coffee-rails (~> 3.2.1)
|
||||
has_many_polymorphs!
|
||||
highline (~> 1.5.0)
|
||||
jquery-rails
|
||||
mysql2
|
||||
rails (= 3.2.3)
|
||||
sass-rails (~> 3.2.3)
|
||||
>>>>>>> initial upgrade to rails 3.2.3
|
||||
sqlite3
|
||||
uglifier (>= 1.0.3)
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
source :gemcutter
|
||||
source "http://gems.github.com/"
|
||||
|
||||
gem "rake", "~>0.8.7"
|
||||
gem "rails", "~>2.3.12"
|
||||
gem "highline", "~>1.5.0"
|
||||
gem "RedCloth", "4.2.8"
|
||||
gem "sanitize", "~>1.2.1"
|
||||
gem "rack", "1.1.0"
|
||||
gem "will_paginate", "~> 2.3.15"
|
||||
gem "has_many_polymorphs", "~> 2.13"
|
||||
gem "acts_as_list", "~>0.1.4"
|
||||
gem "aasm", "~>2.2.0"
|
||||
gem "rubyjedi-actionwebservice", :require => "actionwebservice"
|
||||
gem "rubycas-client", "~>2.2.1"
|
||||
gem "ruby-openid", :require => "openid"
|
||||
|
||||
# you may comment out the database driver you will not be using.
|
||||
# This will prevent a native build of the driver. Building native drivers is not always possible on all hosters
|
||||
gem "sqlite3"
|
||||
gem "mysql"
|
||||
|
||||
gem 'bcrypt-ruby', '~> 2.1.4'
|
||||
gem 'htmlentities', '~> 4.3.0'
|
||||
gem "mail"
|
||||
|
||||
if RUBY_VERSION.to_f >= 1.9
|
||||
gem "soap4r-ruby1.9"
|
||||
else
|
||||
gem "soap4r", "~>1.5.8"
|
||||
end
|
||||
|
||||
group :development do
|
||||
if RUBY_VERSION.to_f >= 1.9
|
||||
gem "ruby-debug19"
|
||||
gem "mongrel", "1.2.0.pre2"
|
||||
else
|
||||
gem "ruby-debug"
|
||||
gem "mongrel"
|
||||
end
|
||||
gem "yard"
|
||||
end
|
||||
|
||||
group :test do
|
||||
gem "test-unit", "1.2.3"
|
||||
gem "flexmock"
|
||||
gem "ZenTest", ">=4.0.0"
|
||||
gem "hpricot"
|
||||
gem "hoe"
|
||||
gem "rspec-rails", "~>1.3.3"
|
||||
gem "thoughtbot-factory_girl"
|
||||
gem 'memory_test_fix', '~>0.1.3'
|
||||
gem "capybara", ">=0.3.5"
|
||||
gem "selenium-webdriver" # Note that > 2.14 has problems: https://code.google.com/p/selenium/issues/detail?id=3075
|
||||
gem "database_cleaner", ">=0.5.0"
|
||||
gem "cucumber-rails", "~>0.3.2"
|
||||
gem "aruba", "0.2.2", :path => "vendor/gems/aruba-0.2.2"
|
||||
|
||||
# uncomment to use the webkit option. This depends on Qt to be installed
|
||||
#gem "capybara-webkit"
|
||||
|
||||
# uncomment to be able to make screenshots from scenarios
|
||||
#gem "capybara-screenshot"
|
||||
#gem "launchy"
|
||||
end
|
|
@ -1,39 +0,0 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
gem 'rails', '3.2.3'
|
||||
|
||||
# Bundle edge Rails instead:
|
||||
# gem 'rails', :git => 'git://github.com/rails/rails.git'
|
||||
|
||||
gem 'sqlite3'
|
||||
gem 'mysql'
|
||||
|
||||
|
||||
# Gems used only for assets and not required
|
||||
# in production environments by default.
|
||||
group :assets do
|
||||
gem 'sass-rails', '~> 3.2.3'
|
||||
gem 'coffee-rails', '~> 3.2.1'
|
||||
|
||||
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
|
||||
# gem 'therubyracer', :platform => :ruby
|
||||
|
||||
gem 'uglifier', '>= 1.0.3'
|
||||
end
|
||||
|
||||
gem 'jquery-rails'
|
||||
|
||||
# To use ActiveModel has_secure_password
|
||||
# gem 'bcrypt-ruby', '~> 3.0.0'
|
||||
|
||||
# To use Jbuilder templates for JSON
|
||||
# gem 'jbuilder'
|
||||
|
||||
# Use unicorn as the app server
|
||||
# gem 'unicorn'
|
||||
|
||||
# Deploy with Capistrano
|
||||
# gem 'capistrano'
|
||||
|
||||
# To use debugger
|
||||
# gem 'ruby-debug19', :require => 'ruby-debug'
|
|
@ -1,22 +0,0 @@
|
|||
class TodoApi < ActionWebService::API::Base
|
||||
api_method :new_todo,
|
||||
:expects => [{:username => :string}, {:token => :string}, {:context_id => :int}, {:description => :string}, {:notes => :string}],
|
||||
:returns => [:int]
|
||||
|
||||
api_method :new_todo_for_project,
|
||||
:expects => [{:username => :string}, {:token => :string}, {:context_id => :int}, {:project_id => :int}, {:description => :string}, {:notes => :string}],
|
||||
:returns => [:int]
|
||||
|
||||
api_method :new_rich_todo,
|
||||
:expects => [{:username => :string}, {:token => :string}, {:default_context_id => :int}, {:description => :string}, {:notes => :string}],
|
||||
:returns => [:int]
|
||||
|
||||
api_method :list_contexts,
|
||||
:expects => [{:username => :string}, {:token => :string}],
|
||||
:returns => [[Context]]
|
||||
|
||||
api_method :list_projects,
|
||||
:expects => [{:username => :string}, {:token => :string}],
|
||||
:returns => [[Project]]
|
||||
|
||||
end
|
|
@ -1,3 +1,332 @@
|
|||
# The filters added to this controller will be run for all controllers in the
|
||||
# application. Likewise will all the methods added be available for all
|
||||
# controllers.
|
||||
|
||||
require_dependency "login_system"
|
||||
require_dependency "tracks/source_view"
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
|
||||
protect_from_forgery
|
||||
|
||||
helper :application
|
||||
include LoginSystem
|
||||
helper_method :current_user, :prefs, :format_date, :markdown
|
||||
|
||||
layout proc{ |controller| controller.mobile? ? "mobile" : "standard" }
|
||||
# exempt_from_layout /\.js\.erb$/
|
||||
|
||||
before_filter :check_for_deprecated_password_hash
|
||||
before_filter :set_session_expiration
|
||||
before_filter :set_time_zone
|
||||
before_filter :set_zindex_counter
|
||||
before_filter :set_locale
|
||||
prepend_before_filter :login_required
|
||||
prepend_before_filter :enable_mobile_content_negotiation
|
||||
after_filter :set_charset
|
||||
|
||||
# By default, sets the charset to UTF-8 if it isn't already set
|
||||
def set_charset
|
||||
headers["Content-Type"] ||= "text/html; charset=UTF-8"
|
||||
end
|
||||
|
||||
def set_locale
|
||||
locale = params[:locale] # specifying a locale in the request takes precedence
|
||||
locale = locale || prefs.locale unless current_user.nil? # otherwise, the locale of the currently logged in user takes over
|
||||
locale = locale || request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first if request.env['HTTP_ACCEPT_LANGUAGE']
|
||||
I18n.locale = locale.nil? ? I18n.default_locale : (I18n::available_locales.include?(locale.to_sym) ? locale : I18n.default_locale)
|
||||
logger.debug("Selected '#{I18n.locale}' as locale")
|
||||
end
|
||||
|
||||
def set_session_expiration
|
||||
# http://wiki.rubyonrails.com/rails/show/HowtoChangeSessionOptions
|
||||
unless session == nil
|
||||
return if self.controller_name == 'feed' or session['noexpiry'] == "on"
|
||||
# If the method is called by the feed controller (which we don't have
|
||||
# under session control) or if we checked the box to keep logged in on
|
||||
# login don't set the session expiry time.
|
||||
if session
|
||||
# Get expiry time (allow ten seconds window for the case where we have
|
||||
# none)
|
||||
expiry_time = session['expiry_time'] || Time.now + 10
|
||||
if expiry_time < Time.now
|
||||
# Too late, matey... bang goes your session!
|
||||
reset_session
|
||||
else
|
||||
# Okay, you get another hour
|
||||
session['expiry_time'] = Time.now + (60*60)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Redirects to change_password_user_path if the current user uses a
|
||||
# deprecated password hashing algorithm.
|
||||
def check_for_deprecated_password_hash
|
||||
if current_user and current_user.uses_deprecated_password?
|
||||
notify :warning, t('users.you_have_to_reset_your_password')
|
||||
redirect_to change_password_user_path current_user
|
||||
end
|
||||
end
|
||||
|
||||
def render_failure message, status = 404
|
||||
render :text => message, :status => status
|
||||
end
|
||||
|
||||
# def rescue_action(exception)
|
||||
# log_error(exception) if logger
|
||||
# respond_to do |format|
|
||||
# format.html do
|
||||
# notify :warning, "An error occurred on the server."
|
||||
# render :action => "index"
|
||||
# end
|
||||
# format.js { render :action => 'error' }
|
||||
# format.xml { render :text => 'An error occurred on the server.' + $! }
|
||||
# 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_phrase(todos_parent, string="actions")
|
||||
count = count_undone_todos(todos_parent)
|
||||
deferred_count = count_deferred_todos(todos_parent)
|
||||
if count == 0 && deferred_count > 0
|
||||
word = deferred_count == 1 ? string.singularize : string.pluralize
|
||||
word = "deferred " + word
|
||||
deferred_count.to_s + " " + word
|
||||
else
|
||||
word = count == 1 ? string.singularize : string.pluralize
|
||||
count.to_s + " " + word
|
||||
end
|
||||
end
|
||||
|
||||
def count_undone_todos(todos_parent)
|
||||
if todos_parent.nil?
|
||||
count = 0
|
||||
elsif (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
|
||||
end
|
||||
|
||||
def count_deferred_todos(todos_parent)
|
||||
if todos_parent.nil?
|
||||
count = 0
|
||||
else
|
||||
count = todos_parent.todos.deferred.count
|
||||
end
|
||||
end
|
||||
|
||||
# Convert a date object to the format specified in the user's preferences in
|
||||
# config/settings.yml
|
||||
#
|
||||
def format_date(date)
|
||||
return date ? date.in_time_zone(prefs.time_zone).strftime("#{prefs.date_format}") : ''
|
||||
end
|
||||
|
||||
def for_autocomplete(coll, substr)
|
||||
if substr # protect agains empty request
|
||||
filtered = coll.find_all{|item| item.name.downcase.include? substr.downcase}
|
||||
json_elems = Array[*filtered.map{ |e| {:id => e.id.to_s, :value => e.name} }].to_json
|
||||
return json_elems
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
def format_dependencies_as_json_for_auto_complete(entries)
|
||||
json_elems = Array[*entries.map{ |e| {:value => e.id.to_s, :label => e.specification} }].to_json
|
||||
return json_elems
|
||||
end
|
||||
|
||||
# Uses RedCloth to transform text using either Textile or Markdown Need to
|
||||
# require redcloth above RedCloth 3.0 or greater is needed to use Markdown,
|
||||
# otherwise it only handles Textile
|
||||
#
|
||||
def markdown(text)
|
||||
RedCloth.new(text).to_html
|
||||
end
|
||||
|
||||
# Here's the concept behind this "mobile content negotiation" hack: In
|
||||
# addition to the main, AJAXy Web UI, Tracks has a lightweight low-feature
|
||||
# 'mobile' version designed to be suitablef or use from a phone or PDA. It
|
||||
# makes some sense that tne pages of that mobile version are simply alternate
|
||||
# representations of the same Todo resources. The implementation goal was to
|
||||
# treat mobile as another format and be able to use respond_to to render both
|
||||
# versions. Unfortunately, I ran into a lot of trouble simply registering a
|
||||
# new mime type 'text/html' with format :m because :html already is linked to
|
||||
# that mime type and the new registration was forcing all html requests to be
|
||||
# rendered in the mobile view. The before_filter and after_filter hackery
|
||||
# below accomplishs that implementation goal by using a 'fake' mime type
|
||||
# during the processing and then setting it to 'text/html' in an
|
||||
# 'after_filter' -LKM 2007-04-01
|
||||
def mobile?
|
||||
return params[:format] == 'm'
|
||||
end
|
||||
|
||||
def enable_mobile_content_negotiation
|
||||
if mobile?
|
||||
request.format = :m
|
||||
end
|
||||
end
|
||||
|
||||
def create_todo_from_recurring_todo(rt, date=nil)
|
||||
# create todo and initialize with data from recurring_todo rt
|
||||
todo = current_user.todos.build( { :description => rt.description, :notes => rt.notes, :project_id => rt.project_id, :context_id => rt.context_id})
|
||||
todo.recurring_todo_id = rt.id
|
||||
|
||||
# set dates
|
||||
todo.due = rt.get_due_date(date)
|
||||
|
||||
show_from_date = rt.get_show_from_date(date)
|
||||
if show_from_date.nil?
|
||||
todo.show_from=nil
|
||||
else
|
||||
# make sure that show_from is not in the past
|
||||
todo.show_from = show_from_date < Time.zone.now ? nil : show_from_date
|
||||
end
|
||||
|
||||
saved = todo.save
|
||||
if saved
|
||||
todo.tag_with(rt.tag_list)
|
||||
todo.tags.reload
|
||||
end
|
||||
|
||||
# increate number of occurences created from recurring todo
|
||||
rt.inc_occurences
|
||||
|
||||
# mark recurring todo complete if there are no next actions left
|
||||
checkdate = todo.due.nil? ? todo.show_from : todo.due
|
||||
rt.toggle_completion! unless rt.has_next_todo(checkdate)
|
||||
|
||||
return saved ? todo : nil
|
||||
end
|
||||
|
||||
def handle_unverified_request
|
||||
unless request.format=="application/xml"
|
||||
super # handle xml http auth via our own login code
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def admin_login_required
|
||||
unless User.find_by_id_and_is_admin(session['user_id'], true)
|
||||
render :text => t('errors.user_unauthorized'), :status => 401
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def redirect_back_or_home
|
||||
respond_to do |format|
|
||||
format.html { redirect_back_or_default home_url }
|
||||
format.m { redirect_back_or_default mobile_url }
|
||||
end
|
||||
end
|
||||
|
||||
def boolean_param(param_name)
|
||||
return false if param_name.blank?
|
||||
s = params[param_name]
|
||||
return false if s.blank? || s == false || s =~ /^false$/i
|
||||
return true if s == true || s =~ /^true$/i
|
||||
raise ArgumentError.new("invalid value for Boolean: \"#{s}\"")
|
||||
end
|
||||
|
||||
def self.openid_enabled?
|
||||
Tracks::Config.openid_enabled?
|
||||
end
|
||||
|
||||
def openid_enabled?
|
||||
self.class.openid_enabled?
|
||||
end
|
||||
|
||||
def self.cas_enabled?
|
||||
Tracks::Config.cas_enabled?
|
||||
end
|
||||
|
||||
def cas_enabled?
|
||||
self.class.cas_enabled?
|
||||
end
|
||||
|
||||
def self.prefered_auth?
|
||||
Tracks::Config.prefered_auth?
|
||||
end
|
||||
|
||||
def prefered_auth?
|
||||
self.class.prefered_auth?
|
||||
end
|
||||
|
||||
# all completed todos [today@00:00, today@now]
|
||||
def get_done_today(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES})
|
||||
start_of_this_day = Time.zone.now.beginning_of_day
|
||||
completed_todos.completed_after(start_of_this_day).all(includes)
|
||||
end
|
||||
|
||||
# all completed todos [begin_of_week, start_of_today]
|
||||
def get_done_this_week(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES})
|
||||
start_of_this_week = Time.zone.now.beginning_of_week
|
||||
start_of_this_day = Time.zone.now.beginning_of_day
|
||||
completed_todos.completed_before(start_of_this_day).completed_after(start_of_this_week).all(includes)
|
||||
end
|
||||
|
||||
# all completed todos [begin_of_month, begin_of_week]
|
||||
def get_done_this_month(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES})
|
||||
start_of_this_month = Time.zone.now.beginning_of_month
|
||||
start_of_this_week = Time.zone.now.beginning_of_week
|
||||
completed_todos.completed_before(start_of_this_week).completed_after(start_of_this_month).all(includes)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_date_per_user_prefs( s )
|
||||
prefs.parse_date(s)
|
||||
end
|
||||
|
||||
def init_data_for_sidebar
|
||||
@completed_projects = current_user.projects.completed
|
||||
@hidden_projects = current_user.projects.hidden
|
||||
@active_projects = current_user.projects.active
|
||||
|
||||
@active_contexts = current_user.contexts.active
|
||||
@hidden_contexts = current_user.contexts.hidden
|
||||
|
||||
init_not_done_counts
|
||||
if prefs.show_hidden_projects_in_sidebar
|
||||
init_project_hidden_todo_counts(['project'])
|
||||
end
|
||||
end
|
||||
|
||||
def init_not_done_counts(parents = ['project','context'])
|
||||
parents.each do |parent|
|
||||
eval("@#{parent}_not_done_counts = @#{parent}_not_done_counts || current_user.todos.active.count(:group => :#{parent}_id)")
|
||||
end
|
||||
end
|
||||
|
||||
def init_project_hidden_todo_counts(parents = ['project','context'])
|
||||
parents.each do |parent|
|
||||
eval("@#{parent}_project_hidden_todo_counts = @#{parent}_project_hidden_todo_counts || current_user.todos.count(:conditions => ['state = ? or state = ?', 'project_hidden', 'active'], :group => :#{parent}_id)")
|
||||
end
|
||||
end
|
||||
|
||||
# Set the contents of the flash message from a controller Usage: notify
|
||||
# :warning, "This is the message" Sets the flash of type 'warning' to "This is
|
||||
# the message"
|
||||
def notify(type, message)
|
||||
flash[type] = message
|
||||
logger.error("ERROR: #{message}") if type == :error
|
||||
end
|
||||
|
||||
def set_time_zone
|
||||
Time.zone = current_user.prefs.time_zone if logged_in?
|
||||
end
|
||||
|
||||
def set_zindex_counter
|
||||
# this counter can be used to handle the IE z-index bug
|
||||
@z_index_counter = 500
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# The methods added to this helper will be available to all templates in the
|
||||
# application.
|
||||
module ApplicationHelper
|
||||
|
||||
# Replicates the link_to method but also checks request.request_uri to find
|
||||
|
|
|
@ -1,301 +0,0 @@
|
|||
# The methods added to this helper will be available to all templates in the
|
||||
# application.
|
||||
module ApplicationHelper
|
||||
|
||||
# Replicates the link_to method but also checks request.request_uri to find
|
||||
# current page. If that matches the url, the link is marked id = "current"
|
||||
#
|
||||
def navigation_link(name, options = {}, html_options = nil, *parameters_for_method_reference)
|
||||
if html_options
|
||||
html_options = html_options.stringify_keys
|
||||
convert_options_to_javascript!(html_options)
|
||||
tag_options = tag_options(html_options)
|
||||
else
|
||||
tag_options = nil
|
||||
end
|
||||
url = options.is_a?(String) ? options : self.url_for(options, *parameters_for_method_reference)
|
||||
id_tag = (request.request_uri == url) ? " id=\"current\"" : ""
|
||||
|
||||
"<a href=\"#{url}\"#{tag_options}#{id_tag}>#{name || url}</a>"
|
||||
end
|
||||
|
||||
def days_from_today(date)
|
||||
date.in_time_zone.to_date - current_user.time.to_date
|
||||
end
|
||||
|
||||
# Check due date in comparison to today's date Flag up date appropriately with
|
||||
# a 'traffic light' colour code
|
||||
#
|
||||
def due_date(due)
|
||||
return "" if due.nil?
|
||||
|
||||
days = days_from_today(due)
|
||||
|
||||
colors = ['amber','amber','orange','orange','orange','orange','orange','orange']
|
||||
color = :red if days < 0
|
||||
color = :green if days > 7
|
||||
color = colors[days] if color.nil?
|
||||
|
||||
return content_tag(:a, {:title => format_date(due)}) {
|
||||
content_tag(:span, {:class => color}) {
|
||||
case days
|
||||
when 0
|
||||
t('todos.next_actions_due_date.due_today')
|
||||
when 1
|
||||
t('todos.next_actions_due_date.due_tomorrow')
|
||||
when 2..7
|
||||
if prefs.due_style == Preference.due_styles[:due_on]
|
||||
# TODO: internationalize strftime here
|
||||
t('models.preference.due_on', :date => due.strftime("%A"))
|
||||
else
|
||||
t('models.preference.due_in', :days => days)
|
||||
end
|
||||
else
|
||||
# overdue or due very soon! sound the alarm!
|
||||
if days == -1
|
||||
t('todos.next_actions_due_date.overdue_by', :days => days * -1)
|
||||
elsif days < -1
|
||||
t('todos.next_actions_due_date.overdue_by_plural', :days => days * -1)
|
||||
else
|
||||
# more than a week away - relax
|
||||
t('models.preference.due_in', :days => days)
|
||||
end
|
||||
end
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
# Check due date in comparison to today's date Flag up date appropriately with
|
||||
# a 'traffic light' colour code Modified method for mobile screen
|
||||
#
|
||||
def due_date_mobile(due)
|
||||
if due == nil
|
||||
return ""
|
||||
end
|
||||
|
||||
days = days_from_today(due)
|
||||
|
||||
case days
|
||||
when 0
|
||||
"<span class=\"amber\">"+ format_date(due) + "</span>"
|
||||
when 1
|
||||
"<span class=\"amber\">" + format_date(due) + "</span>"
|
||||
# due 2-7 days away
|
||||
when 2..7
|
||||
"<span class=\"orange\">" + format_date(due) + "</span>"
|
||||
else
|
||||
# overdue or due very soon! sound the alarm!
|
||||
if days < 0
|
||||
"<span class=\"red\">" + format_date(due) +"</span>"
|
||||
else
|
||||
# more than a week away - relax
|
||||
"<span class=\"green\">" + format_date(due) + "</span>"
|
||||
end
|
||||
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_phrase(todos_parent, string="actions")
|
||||
@controller.count_undone_todos_phrase(todos_parent, string)
|
||||
end
|
||||
|
||||
def count_undone_todos_phrase_text(todos_parent, string="actions")
|
||||
count_undone_todos_phrase(todos_parent, string).gsub(" "," ")
|
||||
end
|
||||
|
||||
def count_undone_todos_and_notes_phrase(project, string="actions")
|
||||
s = count_undone_todos_phrase(project, string)
|
||||
s += ", #{pluralize(project.note_count, 'note')}" unless project.note_count == 0
|
||||
s
|
||||
end
|
||||
|
||||
def link_to_context(context, descriptor = sanitize(context.name))
|
||||
link_to( descriptor, context, :title => "View context: #{context.name}" )
|
||||
end
|
||||
|
||||
def link_to_project(project, descriptor = sanitize(project.name))
|
||||
link_to( descriptor, project, :title => "View project: #{project.name}" )
|
||||
end
|
||||
|
||||
def link_to_edit_note (note, descriptor = sanitize(note.id.to_s))
|
||||
link_to(descriptor,
|
||||
url_for({:controller => 'notes', :action => 'edit', :id => note.id}),
|
||||
{:id => "link_edit_#{dom_id(note)}", :class => "note_edit_settings"})
|
||||
end
|
||||
|
||||
def link_to_project_mobile(project, accesskey, descriptor = sanitize(project.name))
|
||||
link_to( descriptor, project_path(project, :format => 'm'), {:title => "View project: #{project.name}", :accesskey => accesskey} )
|
||||
end
|
||||
|
||||
def item_link_to_context(item)
|
||||
descriptor = "[C]"
|
||||
descriptor = "[#{item.context.name}]" if prefs.verbose_action_descriptors
|
||||
link_to_context( item.context, descriptor )
|
||||
end
|
||||
|
||||
def item_link_to_project(item)
|
||||
descriptor = "[P]"
|
||||
descriptor = "[#{item.project.name}]" if prefs.verbose_action_descriptors
|
||||
link_to_project( item.project, descriptor )
|
||||
end
|
||||
|
||||
def render_flash
|
||||
render :partial => 'shared/flash', :object => flash
|
||||
end
|
||||
|
||||
def recurrence_time_span(rt)
|
||||
case rt.ends_on
|
||||
when "no_end_date"
|
||||
return rt.start_from.nil? ? "" : I18n.t("todos.recurrence.pattern.from") + " " + format_date(rt.start_from)
|
||||
when "ends_on_number_of_times"
|
||||
return I18n.t("todos.recurrence.pattern.times", :number => rt.number_of_occurences)
|
||||
when "ends_on_end_date"
|
||||
starts = rt.start_from.nil? ? "" : I18n.t("todos.recurrence.pattern.from") + " " + format_date(rt.start_from)
|
||||
ends = rt.end_date.nil? ? "" : " " + I18n.t("todos.recurrence.pattern.until") + " " + format_date(rt.end_date)
|
||||
return starts+ends
|
||||
else
|
||||
raise Exception.new, "unknown recurrence time span selection (#{rt.ends_on})"
|
||||
end
|
||||
end
|
||||
|
||||
def recurrence_pattern_as_text(recurring_todo)
|
||||
rt = recurring_todo.recurring_target_as_text
|
||||
rp = recurring_todo.recurrence_pattern
|
||||
# only add space if recurrence_pattern has content
|
||||
rp = " " + rp if !rp.nil?
|
||||
rts = recurrence_time_span(recurring_todo)
|
||||
# only add space if recurrence_time_span has content
|
||||
rts = " " + rts if !(rts == "")
|
||||
return rt+rp+rts
|
||||
end
|
||||
|
||||
def date_format_for_date_picker()
|
||||
standard_format = current_user.prefs.date_format
|
||||
translations = [
|
||||
['%m', 'mm'],
|
||||
['%b', 'M'],
|
||||
['%B', 'MM'],
|
||||
['%d', 'dd'],
|
||||
['%a', 'D'],
|
||||
['%A', 'DD'],
|
||||
['%y', 'y'],
|
||||
['%Y', 'yy']
|
||||
]
|
||||
translations.inject(standard_format) do |str, translation|
|
||||
str.gsub(*translation)
|
||||
end
|
||||
end
|
||||
|
||||
AUTO_LINK_MESSAGE_RE = %r{message://<[^>]+>} unless const_defined?(:AUTO_LINK_MESSAGE_RE)
|
||||
|
||||
# Converts message:// links to href. This URL scheme is used on Mac OS X
|
||||
# to link to a mail message in Mail.app.
|
||||
def auto_link_message(text)
|
||||
text.gsub(AUTO_LINK_MESSAGE_RE) do
|
||||
href = $&
|
||||
left, right = $`, $'
|
||||
# detect already linked URLs and URLs in the middle of a tag
|
||||
if left =~ /<[^>]+$/ && right =~ /^[^>]*>/
|
||||
# do not change string; URL is alreay linked
|
||||
href
|
||||
else
|
||||
content = content_tag(:a, h(href), :href => h(href))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def format_note(note)
|
||||
note = auto_link_message(note)
|
||||
note = markdown(note)
|
||||
note = auto_link(note, :link => :urls)
|
||||
|
||||
# add onenote and message protocols
|
||||
Sanitize::Config::RELAXED[:protocols]['a']['href'] << 'onenote'
|
||||
Sanitize::Config::RELAXED[:protocols]['a']['href'] << 'message'
|
||||
|
||||
note = Sanitize.clean(note, Sanitize::Config::RELAXED)
|
||||
return note
|
||||
end
|
||||
|
||||
def sidebar_html_for_titled_list (list, title)
|
||||
return content_tag(:h3, title+" (#{list.length})") +
|
||||
content_tag(:ul, sidebar_html_for_list(list))
|
||||
end
|
||||
|
||||
def sidebar_html_for_list(list)
|
||||
if list.empty?
|
||||
return content_tag(:li, t('sidebar.list_empty'))
|
||||
else
|
||||
return list.inject("") do |html, item|
|
||||
link = (item.class == "Project") ? link_to_project( item ) : link_to_context(item)
|
||||
html << content_tag(:li, link + " (" + count_undone_todos_phrase(item,"actions")+")")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def generate_i18n_strings
|
||||
js = "i18n_locale='#{I18n.locale}';\n"
|
||||
js << "i18n = new Array();\n"
|
||||
%w{
|
||||
shared.toggle_multi shared.toggle_multi_title
|
||||
shared.hide_form shared.hide_action_form_title
|
||||
shared.toggle_single shared.toggle_single_title
|
||||
projects.hide_form projects.hide_form_title
|
||||
projects.show_form projects.show_form_title
|
||||
contexts.hide_form contexts.hide_form_title
|
||||
contexts.show_form contexts.show_form_title
|
||||
contexts.new_context_pre contexts.new_context_post
|
||||
common.cancel common.ok
|
||||
common.ajaxError todos.unresolved_dependency
|
||||
}.each do |s|
|
||||
js << "i18n['#{s}'] = '#{ t(s).gsub(/'/, "\\\\'") }';\n"
|
||||
end
|
||||
return js
|
||||
end
|
||||
|
||||
def javascript_tag_for_i18n_datepicker
|
||||
locale = I18n.locale
|
||||
# do not include en as locale since this the available by default
|
||||
if locale and locale != :en
|
||||
javascript_include_tag("i18n/jquery.ui.datepicker-#{locale}.js")
|
||||
end
|
||||
end
|
||||
|
||||
def determine_done_path
|
||||
case @controller.controller_name
|
||||
when "contexts"
|
||||
done_todos_context_path(@context)
|
||||
when "projects"
|
||||
done_todos_project_path(@project)
|
||||
when "todos"
|
||||
if source_view_is(:tag)
|
||||
done_tag_path(@tag_name)
|
||||
else
|
||||
done_todos_path
|
||||
end
|
||||
else
|
||||
done_todos_path
|
||||
end
|
||||
end
|
||||
|
||||
def determine_all_done_path
|
||||
case @controller.controller_name
|
||||
when "contexts"
|
||||
all_done_todos_context_path(@context)
|
||||
when "projects"
|
||||
all_done_todos_project_path(@project)
|
||||
when "todos"
|
||||
if source_view_is(:tag)
|
||||
all_done_tag_path(@tag_name)
|
||||
else
|
||||
all_done_todos_path
|
||||
end
|
||||
else
|
||||
all_done_todos_path
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -5,19 +5,19 @@ class Context < ActiveRecord::Base
|
|||
has_many :recurring_todos, :dependent => :delete_all
|
||||
belongs_to :user
|
||||
|
||||
named_scope :active, :conditions => { :hide => false }
|
||||
named_scope :hidden, :conditions => { :hide => true }
|
||||
scope :active, :conditions => { :hide => false }
|
||||
scope :hidden, :conditions => { :hide => true }
|
||||
|
||||
acts_as_list :scope => :user, :top_of_list => 0
|
||||
extend NamePartFinder
|
||||
include Tracks::TodoList
|
||||
# extend NamePartFinder
|
||||
# include Tracks::TodoList
|
||||
|
||||
attr_protected :user
|
||||
|
||||
validates_presence_of :name, :message => "context must have a name"
|
||||
validates_length_of :name, :maximum => 255, :message => "context name must be less than 256 characters"
|
||||
validates_uniqueness_of :name, :message => "already exists", :scope => "user_id"
|
||||
validates_does_not_contain :name, :string => ',', :message => "cannot contain the comma (',') character"
|
||||
# validates_does_not_contain :name, :string => ',', :message => "cannot contain the comma (',') character"
|
||||
|
||||
def self.feed_options(user)
|
||||
# TODO: move to view or helper
|
||||
|
|
|
@ -6,10 +6,10 @@ class Project < ActiveRecord::Base
|
|||
belongs_to :default_context, :class_name => "Context", :foreign_key => "default_context_id"
|
||||
belongs_to :user
|
||||
|
||||
named_scope :active, :conditions => { :state => 'active' }
|
||||
named_scope :hidden, :conditions => { :state => 'hidden' }
|
||||
named_scope :completed, :conditions => { :state => 'completed'}
|
||||
named_scope :uncompleted, :conditions => ["NOT(state = ?)", 'completed']
|
||||
scope :active, :conditions => { :state => 'active' }
|
||||
scope :hidden, :conditions => { :state => 'hidden' }
|
||||
scope :completed, :conditions => { :state => 'completed'}
|
||||
scope :uncompleted, :conditions => ["NOT(state = ?)", 'completed']
|
||||
|
||||
validates_presence_of :name
|
||||
validates_length_of :name, :maximum => 255
|
||||
|
@ -21,8 +21,8 @@ class Project < ActiveRecord::Base
|
|||
aasm_column :state
|
||||
aasm_initial_state :active
|
||||
|
||||
extend NamePartFinder
|
||||
#include Tracks::TodoList
|
||||
# extend NamePartFinder
|
||||
# include Tracks::TodoList
|
||||
|
||||
aasm_state :active
|
||||
aasm_state :hidden, :enter => :hide_todos, :exit => :unhide_todos
|
||||
|
|
|
@ -8,8 +8,8 @@ class RecurringTodo < ActiveRecord::Base
|
|||
|
||||
include IsTaggable
|
||||
|
||||
named_scope :active, :conditions => { :state => 'active'}
|
||||
named_scope :completed, :conditions => { :state => 'completed'}
|
||||
scope :active, :conditions => { :state => 'active'}
|
||||
scope :completed, :conditions => { :state => 'completed'}
|
||||
|
||||
attr_protected :user
|
||||
|
||||
|
|
|
@ -23,33 +23,33 @@ class Todo < ActiveRecord::Base
|
|||
:source => :successor, :conditions => ['todos.state = ?', 'pending']
|
||||
|
||||
# scopes for states of this todo
|
||||
named_scope :active, :conditions => { :state => 'active' }
|
||||
named_scope :active_or_hidden, :conditions => ["todos.state = ? OR todos.state = ?", 'active', 'project_hidden']
|
||||
named_scope :not_completed, :conditions => ['NOT (todos.state = ?)', 'completed']
|
||||
named_scope :completed, :conditions => ["NOT (todos.completed_at IS NULL)"]
|
||||
named_scope :deferred, :conditions => ["todos.completed_at IS NULL AND NOT (todos.show_from IS NULL)"]
|
||||
named_scope :blocked, :conditions => ['todos.state = ?', 'pending']
|
||||
named_scope :pending, :conditions => ['todos.state = ?', 'pending']
|
||||
named_scope :deferred_or_blocked, :conditions => ["(todos.completed_at IS NULL AND NOT(todos.show_from IS NULL)) OR (todos.state = ?)", "pending"]
|
||||
named_scope :not_deferred_or_blocked, :conditions => ["(todos.completed_at IS NULL) AND (todos.show_from IS NULL) AND (NOT todos.state = ?)", "pending"]
|
||||
named_scope :hidden,
|
||||
scope :active, :conditions => { :state => 'active' }
|
||||
scope :active_or_hidden, :conditions => ["todos.state = ? OR todos.state = ?", 'active', 'project_hidden']
|
||||
scope :not_completed, :conditions => ['NOT (todos.state = ?)', 'completed']
|
||||
scope :completed, :conditions => ["NOT (todos.completed_at IS NULL)"]
|
||||
scope :deferred, :conditions => ["todos.completed_at IS NULL AND NOT (todos.show_from IS NULL)"]
|
||||
scope :blocked, :conditions => ['todos.state = ?', 'pending']
|
||||
scope :pending, :conditions => ['todos.state = ?', 'pending']
|
||||
scope :deferred_or_blocked, :conditions => ["(todos.completed_at IS NULL AND NOT(todos.show_from IS NULL)) OR (todos.state = ?)", "pending"]
|
||||
scope :not_deferred_or_blocked, :conditions => ["(todos.completed_at IS NULL) AND (todos.show_from IS NULL) AND (NOT todos.state = ?)", "pending"]
|
||||
scope :hidden,
|
||||
:joins => "INNER JOIN contexts c_hidden ON c_hidden.id = todos.context_id",
|
||||
:conditions => ["todos.state = ? OR (c_hidden.hide = ? AND (todos.state = ? OR todos.state = ? OR todos.state = ?))",
|
||||
'project_hidden', true, 'active', 'deferred', 'pending']
|
||||
named_scope :not_hidden,
|
||||
scope :not_hidden,
|
||||
:joins => "INNER JOIN contexts c_hidden ON c_hidden.id = todos.context_id",
|
||||
:conditions => ['NOT(todos.state = ? OR (c_hidden.hide = ? AND (todos.state = ? OR todos.state = ? OR todos.state = ?)))',
|
||||
'project_hidden', true, 'active', 'deferred', 'pending']
|
||||
|
||||
# other scopes
|
||||
named_scope :are_due, :conditions => ['NOT (todos.due IS NULL)']
|
||||
named_scope :with_tag, lambda { |tag_id| {:joins => :taggings, :conditions => ["taggings.tag_id = ? ", tag_id] } }
|
||||
named_scope :with_tags, lambda { |tag_ids| {:conditions => ["EXISTS(SELECT * from taggings t WHERE t.tag_id IN (?) AND t.taggable_id=todos.id AND t.taggable_type='Todo')", tag_ids] } }
|
||||
named_scope :of_user, lambda { |user_id| {:conditions => ["todos.user_id = ? ", user_id] } }
|
||||
named_scope :completed_after, lambda { |date| {:conditions => ["todos.completed_at > ?", date] } }
|
||||
named_scope :completed_before, lambda { |date| {:conditions => ["todos.completed_at < ?", date] } }
|
||||
named_scope :created_after, lambda { |date| {:conditions => ["todos.created_at > ?", date] } }
|
||||
named_scope :created_before, lambda { |date| {:conditions => ["todos.created_at < ?", date] } }
|
||||
scope :are_due, :conditions => ['NOT (todos.due IS NULL)']
|
||||
scope :with_tag, lambda { |tag_id| {:joins => :taggings, :conditions => ["taggings.tag_id = ? ", tag_id] } }
|
||||
scope :with_tags, lambda { |tag_ids| {:conditions => ["EXISTS(SELECT * from taggings t WHERE t.tag_id IN (?) AND t.taggable_id=todos.id AND t.taggable_type='Todo')", tag_ids] } }
|
||||
scope :of_user, lambda { |user_id| {:conditions => ["todos.user_id = ? ", user_id] } }
|
||||
scope :completed_after, lambda { |date| {:conditions => ["todos.completed_at > ?", date] } }
|
||||
scope :completed_before, lambda { |date| {:conditions => ["todos.completed_at < ?", date] } }
|
||||
scope :created_after, lambda { |date| {:conditions => ["todos.created_at > ?", date] } }
|
||||
scope :created_before, lambda { |date| {:conditions => ["todos.created_at < ?", date] } }
|
||||
|
||||
STARRED_TAG_NAME = "starred"
|
||||
DEFAULT_INCLUDES = [ :project, :context, :tags, :taggings, :pending_successors, :uncompleted_predecessors, :recurring_todo ]
|
||||
|
|
|
@ -9,9 +9,9 @@ class User < ActiveRecord::Base
|
|||
has_many :contexts,
|
||||
:order => 'position ASC',
|
||||
:dependent => :delete_all do
|
||||
def find_by_params(params)
|
||||
find(params['id'] || params['context_id']) || nil
|
||||
end
|
||||
# def find_by_params(params)
|
||||
# find(params['id'] || params['context_id']) || nil
|
||||
# end
|
||||
def update_positions(context_ids)
|
||||
context_ids.each_with_index {|id, position|
|
||||
context = self.detect { |c| c.id == id.to_i }
|
||||
|
@ -23,9 +23,9 @@ class User < ActiveRecord::Base
|
|||
has_many :projects,
|
||||
:order => 'projects.position ASC',
|
||||
:dependent => :delete_all do
|
||||
def find_by_params(params)
|
||||
find(params['id'] || params['project_id'])
|
||||
end
|
||||
# def find_by_params(params)
|
||||
# find(params['id'] || params['project_id'])
|
||||
# end
|
||||
def update_positions(project_ids)
|
||||
project_ids.each_with_index {|id, position|
|
||||
project = self.detect { |p| p.id == id.to_i }
|
||||
|
@ -100,11 +100,11 @@ class User < ActiveRecord::Base
|
|||
validates_confirmation_of :password
|
||||
validates_length_of :login, :within => 3..80
|
||||
validates_uniqueness_of :login, :on => :create
|
||||
validates_presence_of :open_id_url, :if => :using_openid?
|
||||
# validates_presence_of :open_id_url, :if => :using_openid?
|
||||
|
||||
before_create :crypt_password, :generate_token
|
||||
before_update :crypt_password
|
||||
before_save :normalize_open_id_url
|
||||
# before_save :normalize_open_id_url
|
||||
|
||||
#for will_paginate plugin
|
||||
cattr_accessor :per_page
|
||||
|
@ -145,10 +145,10 @@ class User < ActiveRecord::Base
|
|||
return nil
|
||||
end
|
||||
|
||||
def self.find_by_open_id_url(raw_identity_url)
|
||||
normalized_open_id_url = OpenIdAuthentication.normalize_identifier(raw_identity_url)
|
||||
find(:first, :conditions => ['open_id_url = ?', normalized_open_id_url])
|
||||
end
|
||||
# def self.find_by_open_id_url(raw_identity_url)
|
||||
# normalized_open_id_url = OpenIdAuthentication.normalize_identifier(raw_identity_url)
|
||||
# find(:first, :conditions => ['open_id_url = ?', normalized_open_id_url])
|
||||
# end
|
||||
|
||||
def self.no_users_yet?
|
||||
count == 0
|
||||
|
@ -192,7 +192,7 @@ class User < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def generate_token
|
||||
self.token = sha1 "#{Time.now.to_i}#{rand}"
|
||||
self.token = Digest::SHA1.hexdigest "#{Time.now.to_i}#{rand}"
|
||||
end
|
||||
|
||||
def remember_token?
|
||||
|
@ -202,14 +202,14 @@ class User < ActiveRecord::Base
|
|||
# These create and unset the fields required for remembering users between browser closes
|
||||
def remember_me
|
||||
self.remember_token_expires_at = 2.weeks.from_now.utc
|
||||
self.remember_token ||= sha1("#{login}--#{remember_token_expires_at}")
|
||||
save(false)
|
||||
self.remember_token ||= Digest::SHA1.hexdigest("#{login}--#{remember_token_expires_at}")
|
||||
save
|
||||
end
|
||||
|
||||
def forget_me
|
||||
self.remember_token_expires_at = nil
|
||||
self.remember_token = nil
|
||||
save(false)
|
||||
save
|
||||
end
|
||||
|
||||
# Returns true if the user has a password hashed using SHA-1.
|
||||
|
@ -248,19 +248,19 @@ protected
|
|||
auth_type == 'database' && crypted_password.blank? || !password.blank?
|
||||
end
|
||||
|
||||
def using_openid?
|
||||
auth_type == 'open_id'
|
||||
end
|
||||
|
||||
def normalize_open_id_url
|
||||
return if open_id_url.nil?
|
||||
|
||||
# fixup empty url value
|
||||
if open_id_url.empty?
|
||||
self.open_id_url = nil
|
||||
return
|
||||
end
|
||||
|
||||
self.open_id_url = OpenIdAuthentication.normalize_identifier(open_id_url)
|
||||
end
|
||||
# def using_openid?
|
||||
# auth_type == 'open_id'
|
||||
# end
|
||||
#
|
||||
# def normalize_open_id_url
|
||||
# return if open_id_url.nil?
|
||||
#
|
||||
# # fixup empty url value
|
||||
# if open_id_url.empty?
|
||||
# self.open_id_url = nil
|
||||
# return
|
||||
# end
|
||||
#
|
||||
# self.open_id_url = OpenIdAuthentication.normalize_identifier(open_id_url)
|
||||
# end
|
||||
end
|
||||
|
|
|
@ -9,6 +9,9 @@ if defined?(Bundler)
|
|||
# Bundler.require(:default, :assets, Rails.env)
|
||||
end
|
||||
|
||||
require 'yaml'
|
||||
SITE_CONFIG = YAML.load_file(File.join(File.dirname(__FILE__), 'site.yml'))
|
||||
|
||||
module Tracksapp
|
||||
class Application < Rails::Application
|
||||
# Settings in config/environments/* take precedence over those specified here.
|
||||
|
@ -28,6 +31,7 @@ module Tracksapp
|
|||
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
||||
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
||||
# config.time_zone = 'Central Time (US & Canada)'
|
||||
config.time_zone = SITE_CONFIG['time_zone']
|
||||
|
||||
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
||||
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
||||
|
@ -50,10 +54,19 @@ module Tracksapp
|
|||
# parameters by using an attr_accessible or attr_protected declaration.
|
||||
config.active_record.whitelist_attributes = true
|
||||
|
||||
# Set timezone of dates in database
|
||||
config.active_record.default_timezone = :utc
|
||||
|
||||
# Enable the asset pipeline
|
||||
config.assets.enabled = true
|
||||
|
||||
# Version of your assets, change this if you want to expire all your assets
|
||||
config.assets.version = '1.0'
|
||||
|
||||
# configure Tracks to handle deployment in a subdir
|
||||
config.action_controller.relative_url_root = SITE_CONFIG['subdir'] if SITE_CONFIG['subdir']
|
||||
|
||||
# allow onenote:// and message:// as protocols for urls
|
||||
config.action_view.sanitized_allowed_protocols = 'onenote', 'message'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
# MySQL. Versions 4.1 and 5.0 are recommended.
|
||||
#
|
||||
#
|
||||
# Be sure to use new-style password hashing:
|
||||
# http://dev.mysql.com/doc/refman/5.0/en/old-client.html
|
||||
development:
|
||||
adapter: mysql
|
||||
database: tracks_trunk
|
||||
encoding: utf8
|
||||
host: localhost
|
||||
username: tracks
|
||||
password: 32tracks55
|
||||
|
||||
mdevelopment:
|
||||
adapter: sqlite3
|
||||
database: db/tracks-21-test.sqlite3.db
|
||||
|
||||
test: &TEST
|
||||
# adapter: sqlite3
|
||||
# database: ":memory:"
|
||||
# verbosity: quiet
|
||||
adapter: mysql
|
||||
database: tracks_test
|
||||
host: localhost
|
||||
username: tracks
|
||||
password: 32tracks55
|
||||
|
||||
production:
|
||||
adapter: mysql
|
||||
database: tracks_trunk
|
||||
encoding: utf8
|
||||
host: localhost
|
||||
username: tracks
|
||||
password: 32tracks55
|
||||
|
||||
cucumber:
|
||||
<<: *TEST
|
|
@ -1,5 +1,15 @@
|
|||
development:
|
||||
adapter: mysql
|
||||
adapter: mysql2
|
||||
database: tracks
|
||||
# set this if you are storing utf8 in your mysql database to handle strings
|
||||
# like "Réné". Not needed for sqlite. For PostgreSQL use encoding: unicode
|
||||
# encoding: utf8
|
||||
host: localhost
|
||||
username: root
|
||||
password:
|
||||
|
||||
production:
|
||||
adapter: mysql2
|
||||
database: tracks
|
||||
# set this if you are storing utf8 in your mysql database to handle strings
|
||||
# like "Réné".Not needed for sqlite. For PostgreSQL use encoding: unicode
|
||||
|
@ -8,19 +18,21 @@ development:
|
|||
username: root
|
||||
password:
|
||||
|
||||
# The following is an example to configure Tracks to use sqlite
|
||||
|
||||
#production:
|
||||
# adapter: sqlite3
|
||||
# database: db/tracks-20-blank.sqlite3.db
|
||||
# pool: 5
|
||||
# timeout: 5000
|
||||
|
||||
|
||||
# Warning: The database defined as "test" will be erased and
|
||||
# re-generated from your development database when you run "rake".
|
||||
# Do not set this db to the same as development or production.
|
||||
test: &TEST
|
||||
adapter: sqlite3
|
||||
database: ":memory:"
|
||||
|
||||
production:
|
||||
adapter: mysql
|
||||
database: tracks
|
||||
# set this if you are storing utf8 in your mysql database to handle strings
|
||||
# like "Réné".Not needed for sqlite. For PostgreSQL use encoding: unicode
|
||||
# encoding: utf8
|
||||
host: localhost
|
||||
username: root
|
||||
password:
|
||||
|
||||
cucumber:
|
||||
<<: *TEST
|
||||
|
|
|
@ -1,119 +0,0 @@
|
|||
# Be sure to restart your webserver when you modify this file.
|
||||
# Uncomment below to force Rails into production mode
|
||||
|
||||
# (Use only when you can't set environment variables through your web/app server)
|
||||
# ENV['RAILS_ENV'] = 'production'
|
||||
|
||||
# Bootstrap the Rails environment, frameworks, and default configuration
|
||||
require File.join(File.dirname(__FILE__), 'boot')
|
||||
|
||||
require 'yaml'
|
||||
SITE_CONFIG = YAML.load_file(File.join(File.dirname(__FILE__), 'site.yml'))
|
||||
|
||||
class Rails::Configuration
|
||||
attr_accessor :action_web_service
|
||||
end
|
||||
|
||||
Encoding.default_external = Encoding::UTF_8 if RUBY_VERSION > "1.9"
|
||||
|
||||
Rails::Initializer.run do |config|
|
||||
# Skip frameworks you're not going to use
|
||||
# config.frameworks -= [ :action_web_service, :action_mailer ]
|
||||
config.autoload_paths += %W( #{RAILS_ROOT}/app/apis )
|
||||
|
||||
config.action_controller.use_accept_header = true
|
||||
|
||||
# Use the database for sessions instead of the file system
|
||||
# (create the session table with 'rake create_sessions_table')
|
||||
config.action_controller.session_store = :active_record_store
|
||||
|
||||
config.action_controller.session = {
|
||||
:key => '_tracks_session_id',
|
||||
:secret => SITE_CONFIG['salt'] * (30.0 / SITE_CONFIG['salt'].length).ceil #must be at least 30 characters
|
||||
}
|
||||
|
||||
config.action_controller.relative_url_root = SITE_CONFIG['subdir'] if SITE_CONFIG['subdir']
|
||||
|
||||
# Enable page/fragment caching by setting a file-based store
|
||||
# (remember to create the caching directory and make it readable to the application)
|
||||
# config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/cache"
|
||||
|
||||
# Activate observers that should always be running
|
||||
# config.active_record.observers = :cacher, :garbage_collector
|
||||
|
||||
# Make Active Record use UTC-base instead of local time
|
||||
config.active_record.default_timezone = :utc
|
||||
|
||||
# You''ll probably want to change this to the time zone of the computer where Tracks is running
|
||||
# run rake time:zones:local have Rails suggest time zone names on your system
|
||||
config.time_zone = SITE_CONFIG['time_zone']
|
||||
|
||||
# Use Active Record's schema dumper instead of SQL when creating the test database
|
||||
# (enables use of different database adapters for development and test environments)
|
||||
config.active_record.schema_format = :ruby
|
||||
|
||||
# allow other protocols in urls for sanitzer. Add to your liking, for example
|
||||
# config.action_view.sanitized_allowed_protocols = 'onenote', 'blah', 'proto'
|
||||
# to enable "link":onenote://... or "link":blah://... hyperlinks
|
||||
config.action_view.sanitized_allowed_protocols = 'onenote', 'message'
|
||||
|
||||
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
||||
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
||||
# config.i18n.default_locale = :de
|
||||
|
||||
end
|
||||
|
||||
# Add new inflection rules using the following format
|
||||
# (all these examples are active by default):
|
||||
# Inflector.inflections do |inflect|
|
||||
# inflect.plural /^(ox)$/i, '\1en'
|
||||
# inflect.singular /^(ox)en/i, '\1'
|
||||
# inflect.irregular 'person', 'people'
|
||||
# inflect.uncountable %w( fish sheep )
|
||||
# end
|
||||
|
||||
# Include your application configuration below
|
||||
|
||||
|
||||
require 'name_part_finder'
|
||||
require 'tracks/todo_list'
|
||||
require 'tracks/config'
|
||||
require 'tagging_extensions' # Needed for tagging-specific extensions
|
||||
require 'digest/sha1' #Needed to support 'rake db:fixtures:load' on some ruby installs: http://dev.rousette.org.uk/ticket/557
|
||||
|
||||
if ( SITE_CONFIG['authentication_schemes'].include? 'ldap')
|
||||
require 'net/ldap' #requires ruby-net-ldap gem be installed
|
||||
require 'simple_ldap_authenticator'
|
||||
ldap = SITE_CONFIG['ldap']
|
||||
SimpleLdapAuthenticator.ldap_library = ldap['library']
|
||||
SimpleLdapAuthenticator.servers = ldap['servers']
|
||||
SimpleLdapAuthenticator.use_ssl = ldap['ssl']
|
||||
SimpleLdapAuthenticator.login_format = ldap['login_format']
|
||||
end
|
||||
|
||||
if ( SITE_CONFIG['authentication_schemes'].include? 'open_id')
|
||||
#requires ruby-openid gem to be installed
|
||||
OpenID::Util.logger = RAILS_DEFAULT_LOGGER
|
||||
end
|
||||
|
||||
if ( SITE_CONFIG['authentication_schemes'].include? 'cas')
|
||||
#requires rubycas-client gem to be installed
|
||||
if defined? CASClient
|
||||
require 'casclient/frameworks/rails/filter'
|
||||
CASClient::Frameworks::Rails::Filter.configure(
|
||||
:cas_base_url => SITE_CONFIG['cas_server'] ,
|
||||
:cas_server_logout => SITE_CONFIG['cas_server_logout']
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# changed in development.rb to show under_construction bar
|
||||
NOTIFY_BAR = "" unless defined?(NOTIFY_BAR)
|
||||
|
||||
tracks_version='2.2devel'
|
||||
# comment out next two lines if you do not want (or can not) the date of the
|
||||
# last git commit in the footer
|
||||
info=`git log --pretty=format:"%ai" -1`
|
||||
tracks_version=tracks_version + ' ('+info+')'
|
||||
|
||||
TRACKS_VERSION=tracks_version
|
|
@ -1,26 +1,44 @@
|
|||
# Edit at your own peril - it's recommended to regenerate this file
|
||||
# in the future when you upgrade to a newer version of Cucumber.
|
||||
Tracksapp::Application.configure do
|
||||
# Settings specified here will take precedence over those in config/application.rb
|
||||
|
||||
# IMPORTANT: Setting config.cache_classes to false is known to
|
||||
# break Cucumber's use_transactional_fixtures method.
|
||||
# For more information see https://rspec.lighthouseapp.com/projects/16211/tickets/165
|
||||
config.cache_classes = true
|
||||
# The test environment is used exclusively to run your application's
|
||||
# test suite. You never need to work with it otherwise. Remember that
|
||||
# your test database is "scratch space" for the test suite and is wiped
|
||||
# and recreated between test runs. Don't rely on the data there!
|
||||
config.cache_classes = true
|
||||
|
||||
# Log error messages when you accidentally call methods on nil.
|
||||
config.whiny_nils = true
|
||||
# Configure static asset server for tests with Cache-Control for performance
|
||||
config.serve_static_assets = true
|
||||
config.static_cache_control = "public, max-age=3600"
|
||||
|
||||
# Show full error reports and disable caching
|
||||
config.action_controller.consider_all_requests_local = true
|
||||
config.action_controller.perform_caching = false
|
||||
# Log error messages when you accidentally call methods on nil
|
||||
config.whiny_nils = true
|
||||
|
||||
# Disable request forgery protection in test environment
|
||||
config.action_controller.allow_forgery_protection = false
|
||||
# Show full error reports and disable caching
|
||||
config.consider_all_requests_local = true
|
||||
config.action_controller.perform_caching = false
|
||||
|
||||
# Tell Action Mailer not to deliver emails to the real world.
|
||||
# The :test delivery method accumulates sent emails in the
|
||||
# ActionMailer::Base.deliveries array.
|
||||
config.action_mailer.delivery_method = :test
|
||||
# Raise exceptions instead of rendering exception templates
|
||||
config.action_dispatch.show_exceptions = false
|
||||
|
||||
# Unique cookies and use cookies for session
|
||||
config.action_controller.session_store = :cookie_store
|
||||
config.action_controller.session = { :key => 'TracksCucumber', :secret => SITE_CONFIG['salt'] * (30.0 / SITE_CONFIG['salt'].length).ceil }
|
||||
# Disable request forgery protection in test environment
|
||||
config.action_controller.allow_forgery_protection = false
|
||||
|
||||
# Tell Action Mailer not to deliver emails to the real world.
|
||||
# The :test delivery method accumulates sent emails in the
|
||||
# ActionMailer::Base.deliveries array.
|
||||
config.action_mailer.delivery_method = :test
|
||||
|
||||
# Raise exception on mass assignment protection for Active Record models
|
||||
config.active_record.mass_assignment_sanitizer = :strict
|
||||
|
||||
# Print deprecation notices to the stderr
|
||||
config.active_support.deprecation = :stderr
|
||||
|
||||
# Unique cookies and use cookies for session
|
||||
# config.action_controller.session_store :cookie_store, :key => 'TracksCucumber'
|
||||
|
||||
SITE_CONFIG['salt'] ||= 'change-me'
|
||||
|
||||
config.time_zone = 'UTC'
|
||||
end
|
|
@ -34,4 +34,11 @@ Tracksapp::Application.configure do
|
|||
|
||||
# Expands the lines which load the assets
|
||||
config.assets.debug = true
|
||||
|
||||
# Unique cookies
|
||||
# config.action_controller.session_store :cookie_store, :key => 'TracksCucumber'
|
||||
# config.action_controller.session = { :key => 'TracksDev' }
|
||||
|
||||
NOTIFY_BAR="<div id=\"develop-notify-bar\"> </div>"
|
||||
|
||||
end
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
# In the development environment your application's code is reloaded on
|
||||
# every request. This slows down response time but is perfect for development
|
||||
# since you don't have to restart the webserver when you make code changes.
|
||||
config.cache_classes = false
|
||||
|
||||
# Log error messages when you accidentally call methods on nil.
|
||||
config.whiny_nils = true
|
||||
|
||||
# Show full error reports and disable caching
|
||||
config.action_controller.consider_all_requests_local = true
|
||||
config.action_controller.perform_caching = false
|
||||
|
||||
# Don't care if the mailer can't send
|
||||
config.action_mailer.raise_delivery_errors = false
|
||||
|
||||
# Unique cookies
|
||||
config.action_controller.session = { :key => 'TracksDev' }
|
||||
|
||||
NOTIFY_BAR="<div id=\"develop-notify-bar\"> </div>"
|
|
@ -63,5 +63,5 @@ Tracksapp::Application.configure do
|
|||
|
||||
# Log the query plan for queries taking more than this (works
|
||||
# with SQLite, MySQL, and PostgreSQL)
|
||||
# config.active_record.auto_explain_threshold_in_seconds = 0.5
|
||||
config.active_record.auto_explain_threshold_in_seconds = 0.5
|
||||
end
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
# The production environment is meant for finished, "live" apps.
|
||||
# Code is not reloaded between requests
|
||||
config.cache_classes = true
|
||||
|
||||
# Use a different logger for distributed setups
|
||||
# config.logger = SyslogLogger.new
|
||||
|
||||
|
||||
# Full error reports are disabled and caching is turned on
|
||||
config.action_controller.consider_all_requests_local = false
|
||||
config.action_controller.perform_caching = true
|
||||
|
||||
# Enable serving of images, stylesheets, and javascripts from an asset server
|
||||
# config.action_controller.asset_host = "http://assets.example.com"
|
||||
|
||||
# Disable delivery errors if you bad email addresses should just be ignored
|
||||
# config.action_mailer.raise_delivery_errors = false
|
|
@ -34,4 +34,12 @@ Tracksapp::Application.configure do
|
|||
|
||||
# Print deprecation notices to the stderr
|
||||
config.active_support.deprecation = :stderr
|
||||
|
||||
# Unique cookies and use cookies for session
|
||||
# config.action_controller.session_store = :cookie_store
|
||||
# config.action_controller.session = { :key => 'TracksTest', :secret => SITE_CONFIG['salt'] * (30.0 / SITE_CONFIG['salt'].length).ceil }
|
||||
|
||||
SITE_CONFIG['salt'] ||= 'change-me'
|
||||
|
||||
config.time_zone = 'UTC'
|
||||
end
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
# Your secret key for verifying the integrity of signed cookies.
|
||||
# If you change this key, all old signed cookies will become invalid!
|
||||
# Make sure the secret is at least 30 characters and all random,
|
||||
# no regular words or you'll be exposed to dictionary attacks.
|
||||
ActionController::Base.cookie_verifier_secret = 'cdb112742619b87ea7cdcfc9a0f664abaf49dbd12bbc22d9d94ef990b4a0eb9776a9a62ca225e01a014ca8ac8bfda8ae704ce3367b4f75dea3082cea00d6609f';
|
|
@ -1,107 +0,0 @@
|
|||
# adapted from https://gist.github.com/471663 and https://rails.lighthouseapp.com/projects/8994/tickets/4690-mongrel-doesnt-work-with-rails-238
|
||||
|
||||
def check_mongrel_around_115
|
||||
begin
|
||||
# Gem.available? is deprecated from rubygems 1.8.2
|
||||
Gem::Specification::find_by_name "mongrel", "~>1.1.5"
|
||||
rescue
|
||||
if RUBY_VERSION[2] == "9"
|
||||
false
|
||||
else
|
||||
Gem.available?('mongrel', '~>1.1.5')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
mongrel115 = check_mongrel_around_115
|
||||
|
||||
if Rails.version == '2.3.14' && mongrel115 && self.class.const_defined?(:Mongrel)
|
||||
|
||||
# Pulled right from latest rack. Old looked like this in 1.1.0 version.
|
||||
#
|
||||
# def [](k)
|
||||
# super(@names[k] ||= @names[k.downcase])
|
||||
# end
|
||||
#
|
||||
module Rack
|
||||
module Utils
|
||||
class HeaderHash < Hash
|
||||
def [](k)
|
||||
super(@names[k]) if @names[k]
|
||||
super(@names[k.downcase])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Code pulled from the ticket above.
|
||||
#
|
||||
class Mongrel::CGIWrapper
|
||||
def header_with_rails_fix(options = 'text/html')
|
||||
@head['cookie'] = options.delete('cookie').flatten.map { |v| v.sub(/^\n/,'') } if options.class != String and options['cookie']
|
||||
header_without_rails_fix(options)
|
||||
end
|
||||
alias_method_chain :header, :rails_fix
|
||||
end
|
||||
|
||||
# Pulled right from 2.3.10 ActionPack. Simple diff was
|
||||
#
|
||||
# if headers.include?('Set-Cookie')
|
||||
# headers['cookie'] = headers.delete('Set-Cookie').split("\n")
|
||||
# end
|
||||
#
|
||||
# to
|
||||
#
|
||||
# if headers['Set-Cookie']
|
||||
# headers['cookie'] = headers.delete('Set-Cookie').split("\n")
|
||||
# end
|
||||
#
|
||||
module ActionController
|
||||
class CGIHandler
|
||||
def self.dispatch_cgi(app, cgi, out = $stdout)
|
||||
env = cgi.__send__(:env_table)
|
||||
env.delete "HTTP_CONTENT_LENGTH"
|
||||
|
||||
cgi.stdinput.extend ProperStream
|
||||
|
||||
env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
|
||||
|
||||
env.update({
|
||||
"rack.version" => [0,1],
|
||||
"rack.input" => cgi.stdinput,
|
||||
"rack.errors" => $stderr,
|
||||
"rack.multithread" => false,
|
||||
"rack.multiprocess" => true,
|
||||
"rack.run_once" => false,
|
||||
"rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http"
|
||||
})
|
||||
|
||||
env["QUERY_STRING"] ||= ""
|
||||
env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
|
||||
env["REQUEST_PATH"] ||= "/"
|
||||
env.delete "PATH_INFO" if env["PATH_INFO"] == ""
|
||||
|
||||
status, headers, body = app.call(env)
|
||||
begin
|
||||
out.binmode if out.respond_to?(:binmode)
|
||||
out.sync = false if out.respond_to?(:sync=)
|
||||
|
||||
headers['Status'] = status.to_s
|
||||
|
||||
if headers['Set-Cookie']
|
||||
headers['cookie'] = headers.delete('Set-Cookie').split("\n")
|
||||
end
|
||||
|
||||
out.write(cgi.header(headers))
|
||||
|
||||
body.each { |part|
|
||||
out.write part
|
||||
out.flush if out.respond_to?(:flush)
|
||||
}
|
||||
ensure
|
||||
body.close if body.respond_to?(:close)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,21 +0,0 @@
|
|||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
# These settings change the behavior of Rails 2 apps and will be defaults
|
||||
# for Rails 3. You can remove this initializer when Rails 3 is released.
|
||||
|
||||
if defined?(ActiveRecord)
|
||||
# Include Active Record class name as root for JSON serialized output.
|
||||
ActiveRecord::Base.include_root_in_json = true
|
||||
|
||||
# Store the full class name (including module namespace) in STI type column.
|
||||
ActiveRecord::Base.store_full_sti_class = true
|
||||
end
|
||||
|
||||
ActionController::Routing.generate_best_match = false
|
||||
|
||||
# Use ISO 8601 format for JSON serialized times and dates.
|
||||
ActiveSupport.use_standard_json_time_format = true
|
||||
|
||||
# Don't escape HTML entities in JSON, leave that for the #json_escape helper.
|
||||
# if you're including raw json in an HTML page.
|
||||
ActiveSupport.escape_html_entities_in_json = false
|
|
@ -1,8 +1,10 @@
|
|||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
Tracksapp::Application.config.session_store :cookie_store, key: '_tracksapp_session'
|
||||
#Tracksapp::Application.config.session_store :cookie_store, key: '_tracksapp_session'
|
||||
|
||||
# Use the database for sessions instead of the cookie-based default,
|
||||
# which shouldn't be used to store highly confidential information
|
||||
# (create the session table with "rails generate session_migration")
|
||||
# Tracksapp::Application.config.session_store :active_record_store
|
||||
|
||||
Tracksapp::Application.config.session_store :active_record_store, :key => '_tracks_session_id'
|
|
@ -1,21 +0,0 @@
|
|||
begin
|
||||
require "rubygems"
|
||||
require "bundler"
|
||||
rescue LoadError
|
||||
raise "Could not load the bundler gem. Install it with `gem install bundler`."
|
||||
end
|
||||
|
||||
if Gem::Version.new(Bundler::VERSION) <= Gem::Version.new("0.9.24")
|
||||
raise RuntimeError, "Your bundler version is too old for Rails 2.3." +
|
||||
"Run `gem install bundler` to upgrade."
|
||||
end
|
||||
|
||||
begin
|
||||
# Set up load paths for all bundled gems
|
||||
ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)
|
||||
Bundler.setup
|
||||
rescue Bundler::GemNotFound
|
||||
raise RuntimeError, "Bundler couldn't find some gems." +
|
||||
"Did you run `bundle install`?"
|
||||
end
|
||||
|
117
config/routes.rb
117
config/routes.rb
|
@ -55,4 +55,121 @@ Tracksapp::Application.routes.draw do
|
|||
# This is a legacy wild controller route that's not recommended for RESTful applications.
|
||||
# Note: This route will make all actions in every controller accessible via GET requests.
|
||||
# match ':controller(/:action(/:id))(.:format)'
|
||||
|
||||
root :to => 'todos#index'
|
||||
|
||||
match "tickler" => "todos#list_deferred"
|
||||
|
||||
# map.resources :users,
|
||||
# :member => {:change_password => :get, :update_password => :post,
|
||||
# :change_auth_type => :get, :update_auth_type => :post, :complete => :get,
|
||||
# :refresh_token => :post }
|
||||
#
|
||||
# map.with_options :controller => :users do |users|
|
||||
# users.signup 'signup', :action => "new"
|
||||
# end
|
||||
#
|
||||
# map.resources :contexts, :collection => {:order => :post, :done => :get}, :member => {:done_todos => :get, :all_done_todos => :get} do |contexts|
|
||||
# contexts.resources :todos, :name_prefix => "context_"
|
||||
# end
|
||||
#
|
||||
# map.resources :projects,
|
||||
# :collection => {:order => :post, :alphabetize => :post, :actionize => :post, :done => :get},
|
||||
# :member => {:done_todos => :get, :all_done_todos => :get, :set_reviewed => :get} do |projects|
|
||||
# projects.resources :todos, :name_prefix => "project_"
|
||||
# end
|
||||
#
|
||||
# map.with_options :controller => :projects do |projects|
|
||||
# projects.review 'review', :action => :review
|
||||
# end
|
||||
#
|
||||
# map.resources :notes
|
||||
#
|
||||
# map.resources :todos,
|
||||
# :member => {:toggle_check => :put, :toggle_star => :put, :defer => :put},
|
||||
# :collection => {:check_deferred => :post, :filter_to_context => :post, :filter_to_project => :post, :done => :get, :all_done => :get
|
||||
# }
|
||||
#
|
||||
# map.with_options :controller => :todos do |todos|
|
||||
# todos.home '', :action => "index"
|
||||
# todos.tickler 'tickler.:format', :action => "list_deferred"
|
||||
# todos.mobile_tickler 'tickler.m', :action => "list_deferred", :format => 'm'
|
||||
#
|
||||
# # This route works for tags with dots like /todos/tag/version1.5
|
||||
# # please note that this pattern consumes everything after /todos/tag
|
||||
# # so /todos/tag/version1.5.xml will result in :name => 'version1.5.xml'
|
||||
# # UPDATE: added support for mobile view. All tags ending on .m will be
|
||||
# # routed to mobile view of tags.
|
||||
# todos.mobile_tag 'todos/tag/:name.m', :action => "tag", :format => 'm'
|
||||
# todos.text_tag 'todos/tag/:name.txt', :action => "tag", :format => 'txt'
|
||||
# todos.tag 'todos/tag/:name', :action => "tag", :name => /.*/
|
||||
# todos.done_tag 'todos/done/tag/:name', :action => "done_tag"
|
||||
# todos.all_done_tag 'todos/all_done/tag/:name', :action => "all_done_tag"
|
||||
#
|
||||
# todos.tags 'tags.autocomplete', :action => "tags", :format => 'autocomplete'
|
||||
# todos.auto_complete_for_predecessor 'auto_complete_for_predecessor', :action => 'auto_complete_for_predecessor'
|
||||
#
|
||||
# todos.calendar 'calendar.ics', :action => "calendar", :format => 'ics'
|
||||
# todos.calendar 'calendar.xml', :action => "calendar", :format => 'xml'
|
||||
# todos.calendar 'calendar', :action => "calendar"
|
||||
#
|
||||
# todos.hidden 'hidden.xml', :action => "list_hidden", :format => 'xml'
|
||||
#
|
||||
# todos.mobile 'mobile', :action => "index", :format => 'm'
|
||||
# todos.mobile_abbrev 'm', :action => "index", :format => 'm'
|
||||
# todos.mobile_abbrev_new 'm/new', :action => "new", :format => 'm'
|
||||
#
|
||||
# todos.mobile_todo_show_notes 'todos/notes/:id.m', :action => "show_notes", :format => 'm'
|
||||
# todos.todo_show_notes 'todos/notes/:id', :action => "show_notes"
|
||||
# todos.done_todos 'todos/done', :action => :done
|
||||
# todos.all_done_todos 'todos/all_done', :action => :all_done
|
||||
# end
|
||||
# map.root :controller => 'todos' # Make OpenID happy because it needs #root_url defined
|
||||
#
|
||||
# map.resources :recurring_todos, :collection => {:done => :get},
|
||||
# :member => {:toggle_check => :put, :toggle_star => :put}
|
||||
# map.with_options :controller => :recurring_todos do |rt|
|
||||
# rt.recurring_todos 'recurring_todos', :action => 'index'
|
||||
# end
|
||||
#
|
||||
# map.with_options :controller => :login do |login|
|
||||
# login.login 'login', :action => 'login'
|
||||
# login.login_cas 'login_cas', :action => 'login_cas'
|
||||
# login.formatted_login 'login.:format', :action => 'login'
|
||||
# login.logout 'logout', :action => 'logout'
|
||||
# login.formatted_logout 'logout.:format', :action => 'logout'
|
||||
# end
|
||||
#
|
||||
# map.with_options :controller => :feedlist do |fl|
|
||||
# fl.mobile_feeds 'feeds.m', :action => 'index', :format => 'm'
|
||||
# fl.feeds 'feeds', :action => 'index'
|
||||
# end
|
||||
#
|
||||
# map.with_options :controller => :integrations do |i|
|
||||
# i.integrations 'integrations', :action => 'index'
|
||||
# i.rest_api_docs 'integrations/rest_api', :action => "rest_api"
|
||||
# i.search_plugin 'integrations/search_plugin.xml', :action => 'search_plugin', :format => 'xml'
|
||||
# i.google_gadget 'integrations/google_gadget.xml', :action => 'google_gadget', :format => 'xml'
|
||||
# i.cloudmailin 'integrations/cloudmailin', :action => 'cloudmailin'
|
||||
# end
|
||||
#
|
||||
# map.with_options :controller => :preferences do |p|
|
||||
# p.preferences 'preferences', :action => 'index'
|
||||
# p.preferences_date_format 'preferences/render_date_format', :action => 'render_date_format'
|
||||
# end
|
||||
#
|
||||
# map.with_options :controller => :stats do |stats|
|
||||
# stats.stats 'stats', :action => 'index'
|
||||
# stats.done_overview 'done', :action => 'done'
|
||||
# end
|
||||
#
|
||||
# map.search 'search', :controller => 'search', :action => 'index'
|
||||
# map.data 'data', :controller => 'data', :action => 'index'
|
||||
#
|
||||
# Translate::Routes.translation_ui(map) if Rails.env != "production"
|
||||
#
|
||||
# # Install the default route as the lowest priority.
|
||||
# map.connect ':controller/:action/:id'
|
||||
#
|
||||
|
||||
end
|
||||
|
|
|
@ -1,113 +0,0 @@
|
|||
ActionController::Routing::Routes.draw do |map|
|
||||
map.resources :users,
|
||||
:member => {:change_password => :get, :update_password => :post,
|
||||
:change_auth_type => :get, :update_auth_type => :post, :complete => :get,
|
||||
:refresh_token => :post }
|
||||
|
||||
map.with_options :controller => :users do |users|
|
||||
users.signup 'signup', :action => "new"
|
||||
end
|
||||
|
||||
map.resources :contexts, :collection => {:order => :post, :done => :get}, :member => {:done_todos => :get, :all_done_todos => :get} do |contexts|
|
||||
contexts.resources :todos, :name_prefix => "context_"
|
||||
end
|
||||
|
||||
map.resources :projects,
|
||||
:collection => {:order => :post, :alphabetize => :post, :actionize => :post, :done => :get},
|
||||
:member => {:done_todos => :get, :all_done_todos => :get, :set_reviewed => :get} do |projects|
|
||||
projects.resources :todos, :name_prefix => "project_"
|
||||
end
|
||||
|
||||
map.with_options :controller => :projects do |projects|
|
||||
projects.review 'review', :action => :review
|
||||
end
|
||||
|
||||
map.resources :notes
|
||||
|
||||
map.resources :todos,
|
||||
:member => {:toggle_check => :put, :toggle_star => :put, :defer => :put},
|
||||
:collection => {:check_deferred => :post, :filter_to_context => :post, :filter_to_project => :post, :done => :get, :all_done => :get
|
||||
}
|
||||
|
||||
map.with_options :controller => :todos do |todos|
|
||||
todos.home '', :action => "index"
|
||||
todos.tickler 'tickler.:format', :action => "list_deferred"
|
||||
todos.mobile_tickler 'tickler.m', :action => "list_deferred", :format => 'm'
|
||||
|
||||
# This route works for tags with dots like /todos/tag/version1.5
|
||||
# please note that this pattern consumes everything after /todos/tag
|
||||
# so /todos/tag/version1.5.xml will result in :name => 'version1.5.xml'
|
||||
# UPDATE: added support for mobile view. All tags ending on .m will be
|
||||
# routed to mobile view of tags.
|
||||
todos.mobile_tag 'todos/tag/:name.m', :action => "tag", :format => 'm'
|
||||
todos.text_tag 'todos/tag/:name.txt', :action => "tag", :format => 'txt'
|
||||
todos.tag 'todos/tag/:name', :action => "tag", :name => /.*/
|
||||
todos.done_tag 'todos/done/tag/:name', :action => "done_tag"
|
||||
todos.all_done_tag 'todos/all_done/tag/:name', :action => "all_done_tag"
|
||||
|
||||
todos.tags 'tags.autocomplete', :action => "tags", :format => 'autocomplete'
|
||||
todos.auto_complete_for_predecessor 'auto_complete_for_predecessor', :action => 'auto_complete_for_predecessor'
|
||||
|
||||
todos.calendar 'calendar.ics', :action => "calendar", :format => 'ics'
|
||||
todos.calendar 'calendar.xml', :action => "calendar", :format => 'xml'
|
||||
todos.calendar 'calendar', :action => "calendar"
|
||||
|
||||
todos.hidden 'hidden.xml', :action => "list_hidden", :format => 'xml'
|
||||
|
||||
todos.mobile 'mobile', :action => "index", :format => 'm'
|
||||
todos.mobile_abbrev 'm', :action => "index", :format => 'm'
|
||||
todos.mobile_abbrev_new 'm/new', :action => "new", :format => 'm'
|
||||
|
||||
todos.mobile_todo_show_notes 'todos/notes/:id.m', :action => "show_notes", :format => 'm'
|
||||
todos.todo_show_notes 'todos/notes/:id', :action => "show_notes"
|
||||
todos.done_todos 'todos/done', :action => :done
|
||||
todos.all_done_todos 'todos/all_done', :action => :all_done
|
||||
end
|
||||
map.root :controller => 'todos' # Make OpenID happy because it needs #root_url defined
|
||||
|
||||
map.resources :recurring_todos, :collection => {:done => :get},
|
||||
:member => {:toggle_check => :put, :toggle_star => :put}
|
||||
map.with_options :controller => :recurring_todos do |rt|
|
||||
rt.recurring_todos 'recurring_todos', :action => 'index'
|
||||
end
|
||||
|
||||
map.with_options :controller => :login do |login|
|
||||
login.login 'login', :action => 'login'
|
||||
login.login_cas 'login_cas', :action => 'login_cas'
|
||||
login.formatted_login 'login.:format', :action => 'login'
|
||||
login.logout 'logout', :action => 'logout'
|
||||
login.formatted_logout 'logout.:format', :action => 'logout'
|
||||
end
|
||||
|
||||
map.with_options :controller => :feedlist do |fl|
|
||||
fl.mobile_feeds 'feeds.m', :action => 'index', :format => 'm'
|
||||
fl.feeds 'feeds', :action => 'index'
|
||||
end
|
||||
|
||||
map.with_options :controller => :integrations do |i|
|
||||
i.integrations 'integrations', :action => 'index'
|
||||
i.rest_api_docs 'integrations/rest_api', :action => "rest_api"
|
||||
i.search_plugin 'integrations/search_plugin.xml', :action => 'search_plugin', :format => 'xml'
|
||||
i.google_gadget 'integrations/google_gadget.xml', :action => 'google_gadget', :format => 'xml'
|
||||
i.cloudmailin 'integrations/cloudmailin', :action => 'cloudmailin'
|
||||
end
|
||||
|
||||
map.with_options :controller => :preferences do |p|
|
||||
p.preferences 'preferences', :action => 'index'
|
||||
p.preferences_date_format 'preferences/render_date_format', :action => 'render_date_format'
|
||||
end
|
||||
|
||||
map.with_options :controller => :stats do |stats|
|
||||
stats.stats 'stats', :action => 'index'
|
||||
stats.done_overview 'done', :action => 'done'
|
||||
end
|
||||
|
||||
map.search 'search', :controller => 'search', :action => 'index'
|
||||
map.data 'data', :controller => 'data', :action => 'index'
|
||||
|
||||
Translate::Routes.translation_ui(map) if Rails.env != "production"
|
||||
|
||||
# Install the default route as the lowest priority.
|
||||
map.connect ':controller/:action/:id'
|
||||
|
||||
end
|
|
@ -5,10 +5,10 @@ salt: "change-me"
|
|||
|
||||
# Uncomment ldap or open_id if you want to use those authentication schemes.
|
||||
# If you choose ldap, see the additional configuration options further down.
|
||||
# NOTE: openid is not supported anymore.
|
||||
authentication_schemes:
|
||||
- "database"
|
||||
# - "ldap"
|
||||
# - "open_id"
|
||||
# - "cas"
|
||||
|
||||
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
Use this README file to introduce your application and point to useful places in the API for learning more.
|
||||
Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.
|
|
@ -1,113 +0,0 @@
|
|||
module AuthenticatedTestHelper
|
||||
# Sets the current user in the session from the user fixtures.
|
||||
def login_as(user)
|
||||
@request.session['user_id'] = user ? users(user).id : nil
|
||||
end
|
||||
|
||||
def content_type(type)
|
||||
@request.env['Content-Type'] = type
|
||||
end
|
||||
|
||||
def accept(accept)
|
||||
@request.env["HTTP_ACCEPT"] = accept
|
||||
end
|
||||
|
||||
def authorize_as(user)
|
||||
if user
|
||||
@request.env["HTTP_AUTHORIZATION"] = "Basic #{Base64.encode64("#{users(user).login}:test")}"
|
||||
accept 'application/xml'
|
||||
content_type 'application/xml'
|
||||
else
|
||||
@request.env["HTTP_AUTHORIZATION"] = nil
|
||||
accept nil
|
||||
content_type nil
|
||||
end
|
||||
end
|
||||
|
||||
# http://project.ioni.st/post/217#post-217
|
||||
#
|
||||
# def test_new_publication
|
||||
# assert_difference(Publication, :count) do
|
||||
# post :create, :publication => {...}
|
||||
# # ...
|
||||
# end
|
||||
# end
|
||||
#
|
||||
def assert_difference(object, method = nil, difference = 1)
|
||||
initial_value = object.send(method)
|
||||
yield
|
||||
assert_equal initial_value + difference, object.send(method), "#{object}##{method}"
|
||||
end
|
||||
|
||||
def assert_no_difference(object, method, &block)
|
||||
assert_difference object, method, 0, &block
|
||||
end
|
||||
|
||||
# Assert the block redirects to the login
|
||||
#
|
||||
# assert_requires_login(:bob) { |c| c.get :edit, :id => 1 }
|
||||
#
|
||||
def assert_requires_login(login = nil)
|
||||
yield HttpLoginProxy.new(self, login)
|
||||
end
|
||||
|
||||
def assert_http_authentication_required(login = nil)
|
||||
yield XmlLoginProxy.new(self, login)
|
||||
end
|
||||
|
||||
def reset!(*instance_vars)
|
||||
instance_vars = [:controller, :request, :response] unless instance_vars.any?
|
||||
instance_vars.collect! { |v| "@#{v}".to_sym }
|
||||
instance_vars.each do |var|
|
||||
instance_variable_set(var, instance_variable_get(var).class.new)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class BaseLoginProxy
|
||||
attr_reader :controller
|
||||
attr_reader :options
|
||||
def initialize(controller, login)
|
||||
@controller = controller
|
||||
@login = login
|
||||
end
|
||||
|
||||
private
|
||||
def authenticated
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def check
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def method_missing(method, *args)
|
||||
@controller.reset!
|
||||
authenticate
|
||||
@controller.send(method, *args)
|
||||
check
|
||||
end
|
||||
end
|
||||
|
||||
class HttpLoginProxy < BaseLoginProxy
|
||||
protected
|
||||
def authenticate
|
||||
@controller.login_as @login if @login
|
||||
end
|
||||
|
||||
def check
|
||||
@controller.assert_redirected_to :controller => 'account', :action => 'login'
|
||||
end
|
||||
end
|
||||
|
||||
class XmlLoginProxy < BaseLoginProxy
|
||||
protected
|
||||
def authenticate
|
||||
@controller.accept 'application/xml'
|
||||
@controller.authorize_as @login if @login
|
||||
end
|
||||
|
||||
def check
|
||||
@controller.assert_response 401
|
||||
end
|
||||
end
|
|
@ -59,7 +59,8 @@ module LoginSystem
|
|||
# cookie and log the user back in if appropriate
|
||||
def login_from_cookie
|
||||
return unless cookies[:auth_token] && !logged_in?
|
||||
user = User.find_by_remember_token(cookies[:auth_token])
|
||||
token = cookies[:auth_token]
|
||||
user = User.find_by_remember_token(token)
|
||||
if user && user.remember_token?
|
||||
session['user_id'] = user.id
|
||||
set_current_user(user)
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
module NamePartFinder
|
||||
def find_by_namepart(namepart)
|
||||
find_by_name(namepart) || find(:first, :conditions => ["name LIKE ?", namepart + '%'])
|
||||
end
|
||||
end
|
|
@ -1,38 +0,0 @@
|
|||
# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril.
|
||||
# It is recommended to regenerate this file in the future when you upgrade to a
|
||||
# newer version of cucumber-rails. Consider adding your own code to a new file
|
||||
# instead of editing this one. Cucumber will automatically load all features/**/*.rb
|
||||
# files.
|
||||
|
||||
vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
|
||||
$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil?
|
||||
|
||||
begin
|
||||
require 'cucumber/rake/task'
|
||||
|
||||
namespace :cucumber do
|
||||
Cucumber::Rake::Task.new({:selenium => :env_to_selenium}, 'Run features that require selenium') do |t|
|
||||
t.binary = vendored_cucumber_bin
|
||||
t.fork = true # You may get faster startup if you set this to false
|
||||
t.profile = 'selenium'
|
||||
end
|
||||
|
||||
Cucumber::Rake::Task.new({:selenium_wip => :env_to_selenium}, 'Run unfinished features that require selenium') do |t|
|
||||
t.binary = vendored_cucumber_bin
|
||||
t.fork = true # You may get faster startup if you set this to false
|
||||
t.profile = 'selenium_wip'
|
||||
end
|
||||
|
||||
task :env_to_selenium => 'db:test:prepare' do
|
||||
ENV['RAILS_ENV'] = 'selenium'
|
||||
end
|
||||
|
||||
desc 'Run all features'
|
||||
task :all => [:ok, :wip, :selenium, :selenium_wip]
|
||||
end
|
||||
rescue LoadError
|
||||
desc 'cucumber rake task not available (cucumber not installed)'
|
||||
task :cucumber do
|
||||
abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'
|
||||
end
|
||||
end
|
|
@ -1,53 +0,0 @@
|
|||
# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril.
|
||||
# It is recommended to regenerate this file in the future when you upgrade to a
|
||||
# newer version of cucumber-rails. Consider adding your own code to a new file
|
||||
# instead of editing this one. Cucumber will automatically load all features/**/*.rb
|
||||
# files.
|
||||
|
||||
|
||||
unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks
|
||||
|
||||
vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
|
||||
$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil?
|
||||
|
||||
begin
|
||||
require 'cucumber/rake/task'
|
||||
|
||||
namespace :cucumber do
|
||||
Cucumber::Rake::Task.new({:ok => 'db:test:prepare'}, 'Run features that should pass') do |t|
|
||||
t.binary = vendored_cucumber_bin # If nil, the gem's binary is used.
|
||||
t.fork = true # You may get faster startup if you set this to false
|
||||
t.profile = 'default'
|
||||
end
|
||||
|
||||
Cucumber::Rake::Task.new({:wip => 'db:test:prepare'}, 'Run features that are being worked on') do |t|
|
||||
t.binary = vendored_cucumber_bin
|
||||
t.fork = true # You may get faster startup if you set this to false
|
||||
t.profile = 'wip'
|
||||
end
|
||||
|
||||
Cucumber::Rake::Task.new({:rerun => 'db:test:prepare'}, 'Record failing features and run only them if any exist') do |t|
|
||||
t.binary = vendored_cucumber_bin
|
||||
t.fork = true # You may get faster startup if you set this to false
|
||||
t.profile = 'rerun'
|
||||
end
|
||||
|
||||
desc 'Run all features'
|
||||
task :all => [:ok, :wip]
|
||||
end
|
||||
desc 'Alias for cucumber:ok'
|
||||
task :cucumber => 'cucumber:ok'
|
||||
|
||||
task :default => :cucumber
|
||||
|
||||
task :features => :cucumber do
|
||||
STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***"
|
||||
end
|
||||
rescue LoadError
|
||||
desc 'cucumber rake task not available (cucumber not installed)'
|
||||
task :cucumber do
|
||||
abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
require 'rake'
|
||||
|
||||
namespace :db do
|
||||
desc "Dump the current SQLite3 or MySQL database to a sql file"
|
||||
task :dump_sql do
|
||||
load 'config/environment.rb'
|
||||
abcs = ActiveRecord::Base.configurations
|
||||
case abcs[RAILS_ENV]["adapter"]
|
||||
when 'mysql'
|
||||
ActiveRecord::Base.establish_connection(abcs[RAILS_ENV])
|
||||
File.open("db/#{RAILS_ENV}_data.sql", "w+") do |f|
|
||||
if abcs[RAILS_ENV]["password"].blank?
|
||||
f << `mysqldump -h #{abcs[RAILS_ENV]["host"]} -u #{abcs[RAILS_ENV]["username"]} #{abcs[RAILS_ENV]["database"]}`
|
||||
else
|
||||
f << `mysqldump -h #{abcs[RAILS_ENV]["host"]} -u #{abcs[RAILS_ENV]["username"]} -p#{abcs[RAILS_ENV]["password"]} #{abcs[RAILS_ENV]["database"]}`
|
||||
end
|
||||
end
|
||||
when 'sqlite3'
|
||||
ActiveRecord::Base.establish_connection(abcs[RAILS_ENV])
|
||||
File.open("db/#{RAILS_ENV}_data.sql", "w+") do |f|
|
||||
f << `sqlite3 #{abcs[RAILS_ENV]["database"]} .dump`
|
||||
end
|
||||
else
|
||||
raise "Task not supported by '#{abcs[RAILS_ENV]['adapter']}'"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,17 +0,0 @@
|
|||
desc ' Create YAML test fixtures from data in an existing database.
|
||||
Defaults to development database. Set RAILS_ENV to override (taken from Rails Recipes book).'
|
||||
task :extract_fixtures => :environment do
|
||||
sql = "SELECT * FROM %s"
|
||||
skip_tables = ["schema_info", "sessions", "users"]
|
||||
ActiveRecord::Base.establish_connection
|
||||
(ActiveRecord::Base.connection.tables - skip_tables).each do |table_name|
|
||||
i = "000"
|
||||
File.open("#{RAILS_ROOT}/db/exported_fixtures/#{table_name}.yml", 'w' ) do |file|
|
||||
data = ActiveRecord::Base.connection.select_all(sql % table_name)
|
||||
file.write data.inject({}) { |hash, record|
|
||||
hash["#{table_name}_#{i.succ!}"] = record
|
||||
hash
|
||||
}.to_yaml
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,34 +0,0 @@
|
|||
desc "Copy third-party gems into ./lib"
|
||||
task :freeze_other_gems do
|
||||
# TODO Get this list from parsing environment.rb
|
||||
libraries = %w(redcloth)
|
||||
require 'rubygems'
|
||||
require 'find'
|
||||
|
||||
libraries.each do |library|
|
||||
library_gem = Gem.cache.search(library).sort_by { |g| g.version }.last
|
||||
puts "Freezing #{library} for #{library_gem.version}..."
|
||||
|
||||
# TODO Add dependencies to list of libraries to freeze
|
||||
#library_gem.dependencies.each { |g| libraries << g }
|
||||
|
||||
folder_for_library = "#{library_gem.name}-#{library_gem.version}"
|
||||
system "cd vendor; gem unpack -v '#{library_gem.version}' #{library_gem.name};"
|
||||
|
||||
# Copy files recursively to ./lib
|
||||
folder_for_library_with_lib = "vendor/#{folder_for_library}/lib/"
|
||||
Find.find(folder_for_library_with_lib) do |original_file|
|
||||
destination_file = "./lib/" + original_file.gsub(folder_for_library_with_lib, '')
|
||||
|
||||
if File.directory?(original_file)
|
||||
if !File.exist?(destination_file)
|
||||
Dir.mkdir destination_file
|
||||
end
|
||||
else
|
||||
File.copy original_file, destination_file
|
||||
end
|
||||
end
|
||||
|
||||
system "rm -r vendor/#{folder_for_library}"
|
||||
end
|
||||
end
|
|
@ -1,8 +0,0 @@
|
|||
desc "Load exported fixtures (in db/exported_fixtures) into the current environment's database"
|
||||
task :load_exported_fixtures => :environment do
|
||||
require 'active_record/fixtures'
|
||||
ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
|
||||
Dir.glob(File.join(RAILS_ROOT, 'db', 'exported_fixtures', '*.{yml,csv}')).each do |fixture_file|
|
||||
Fixtures.create_fixtures('db/exported_fixtures', File.basename(fixture_file, '.*'))
|
||||
end
|
||||
end
|
|
@ -1,50 +0,0 @@
|
|||
namespace :query_trace do
|
||||
desc "Enables the query_trace plugin. Must restart server to take effect."
|
||||
task :on => :environment do
|
||||
unless File.exist?("#{RAILS_ROOT}/vendor/query_trace.tar.gz")
|
||||
Dir.chdir("#{RAILS_ROOT}/vendor") do
|
||||
url = "https://terralien.devguard.com/svn/projects/plugins/query_trace"
|
||||
puts "Loading query_trace from #{url}..."
|
||||
system "svn co #{url} query_trace"
|
||||
system "tar zcf query_trace.tar.gz --exclude=.svn query_trace"
|
||||
FileUtils.rm_rf("query_trace")
|
||||
end
|
||||
end
|
||||
Dir.chdir("#{RAILS_ROOT}/vendor/plugins") do
|
||||
system "tar zxf ../query_trace.tar.gz query_trace"
|
||||
end
|
||||
puts "QueryTrace plugin enabled. Must restart server to take effect."
|
||||
end
|
||||
|
||||
desc "Disables the query_trace plugin. Must restart server to take effect."
|
||||
task :off => :environment do
|
||||
FileUtils.rm_rf("#{RAILS_ROOT}/vendor/plugins/query_trace")
|
||||
puts "QueryTrace plugin disabled. Must restart server to take effect."
|
||||
end
|
||||
end
|
||||
|
||||
namespace :query_analyzer do
|
||||
desc "Enables the query_analyzer plugin. Must restart server to take effect."
|
||||
task :on => :environment do
|
||||
unless File.exist?("#{RAILS_ROOT}/vendor/query_analyzer.tar.gz")
|
||||
Dir.chdir("#{RAILS_ROOT}/vendor") do
|
||||
url = "http://svn.nfectio.us/plugins/query_analyzer"
|
||||
puts "Loading query_analyzer from #{url}..."
|
||||
system "svn co #{url} query_analyzer"
|
||||
system "tar zcf query_analyzer.tar.gz --exclude=.svn query_analyzer"
|
||||
FileUtils.rm_rf("query_analyzer")
|
||||
end
|
||||
end
|
||||
Dir.chdir("#{RAILS_ROOT}/vendor/plugins") do
|
||||
system "tar zxf ../query_analyzer.tar.gz query_analyzer"
|
||||
end
|
||||
puts "QueryAnalyzer plugin enabled. Must restart server to take effect."
|
||||
end
|
||||
|
||||
desc "Disables the query_analyzer plugin. Must restart server to take effect."
|
||||
task :off => :environment do
|
||||
FileUtils.rm_rf("#{RAILS_ROOT}/vendor/plugins/query_analyzer")
|
||||
puts "QueryAnalyzer plugin disabled. Must restart server to take effect."
|
||||
end
|
||||
end
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
namespace :tracks do
|
||||
desc 'Replace the password of USER with a new one.'
|
||||
task :password => :environment do
|
||||
require "highline/import"
|
||||
|
||||
user = User.find_by_login(ENV['USER'])
|
||||
if user.nil?
|
||||
puts "Sorry, we couldn't find user '#{ENV['USER']}'. To specify a different user, pass USER=username to this task."
|
||||
exit 0
|
||||
end
|
||||
|
||||
puts "Changing Tracks password for #{ENV['USER']}."
|
||||
password = ask("New password: ") { |q| q.echo = false }
|
||||
password_confirmation = ask('Retype new password: ') { |q| q.echo = false }
|
||||
|
||||
begin
|
||||
user.change_password(password, password_confirmation)
|
||||
rescue ActiveRecord::RecordInvalid
|
||||
puts "Sorry, we couldn't change #{ENV['USER']}'s password: "
|
||||
user.errors.each_full { |msg| puts "- #{msg}\n" }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,144 +0,0 @@
|
|||
gem 'test-unit', '1.2.3' if RUBY_VERSION.to_f >= 1.9
|
||||
rspec_gem_dir = nil
|
||||
Dir["#{RAILS_ROOT}/vendor/gems/*"].each do |subdir|
|
||||
rspec_gem_dir = subdir if subdir.gsub("#{RAILS_ROOT}/vendor/gems/","") =~ /^(\w+-)?rspec-(\d+)/ && File.exist?("#{subdir}/lib/spec/rake/spectask.rb")
|
||||
end
|
||||
rspec_plugin_dir = File.expand_path(File.dirname(__FILE__) + '/../../vendor/plugins/rspec')
|
||||
|
||||
if rspec_gem_dir && (test ?d, rspec_plugin_dir)
|
||||
raise "\n#{'*'*50}\nYou have rspec installed in both vendor/gems and vendor/plugins\nPlease pick one and dispose of the other.\n#{'*'*50}\n\n"
|
||||
end
|
||||
|
||||
if rspec_gem_dir
|
||||
$LOAD_PATH.unshift("#{rspec_gem_dir}/lib")
|
||||
elsif File.exist?(rspec_plugin_dir)
|
||||
$LOAD_PATH.unshift("#{rspec_plugin_dir}/lib")
|
||||
end
|
||||
|
||||
# Don't load rspec if running "rake gems:*"
|
||||
unless ARGV.any? {|a| a =~ /^gems/}
|
||||
|
||||
begin
|
||||
require 'spec/rake/spectask'
|
||||
rescue MissingSourceFile
|
||||
module Spec
|
||||
module Rake
|
||||
class SpecTask
|
||||
def initialize(name)
|
||||
task name do
|
||||
# if rspec-rails is a configured gem, this will output helpful material and exit ...
|
||||
require File.expand_path(File.join(File.dirname(__FILE__),"..","..","config","environment"))
|
||||
|
||||
# ... otherwise, do this:
|
||||
raise <<-MSG
|
||||
|
||||
#{"*" * 80}
|
||||
* You are trying to run an rspec rake task defined in
|
||||
* #{__FILE__},
|
||||
* but rspec can not be found in vendor/gems, vendor/plugins or system gems.
|
||||
#{"*" * 80}
|
||||
MSG
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Rake.application.instance_variable_get('@tasks').delete('default')
|
||||
|
||||
spec_prereq = File.exist?(File.join(RAILS_ROOT, 'config', 'database.yml')) ? "db:test:prepare" : :noop
|
||||
task :noop do
|
||||
end
|
||||
|
||||
task :default => :spec
|
||||
task :stats => "spec:statsetup"
|
||||
|
||||
desc "Run all specs in spec directory (excluding plugin specs)"
|
||||
Spec::Rake::SpecTask.new(:spec => spec_prereq) do |t|
|
||||
t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""]
|
||||
t.spec_files = FileList['spec/**/*_spec.rb']
|
||||
end
|
||||
|
||||
namespace :spec do
|
||||
desc "Run all specs in spec directory with RCov (excluding plugin specs)"
|
||||
Spec::Rake::SpecTask.new(:rcov) do |t|
|
||||
t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""]
|
||||
t.spec_files = FileList['spec/**/*_spec.rb']
|
||||
t.rcov = true
|
||||
t.rcov_opts = lambda do
|
||||
IO.readlines("#{RAILS_ROOT}/spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
|
||||
end
|
||||
end
|
||||
|
||||
desc "Print Specdoc for all specs (excluding plugin specs)"
|
||||
Spec::Rake::SpecTask.new(:doc) do |t|
|
||||
t.spec_opts = ["--format", "specdoc", "--dry-run"]
|
||||
t.spec_files = FileList['spec/**/*_spec.rb']
|
||||
end
|
||||
|
||||
desc "Print Specdoc for all plugin examples"
|
||||
Spec::Rake::SpecTask.new(:plugin_doc) do |t|
|
||||
t.spec_opts = ["--format", "specdoc", "--dry-run"]
|
||||
t.spec_files = FileList['vendor/plugins/**/spec/**/*_spec.rb'].exclude('vendor/plugins/rspec/*')
|
||||
end
|
||||
|
||||
[:models, :controllers, :views, :helpers, :lib, :integration].each do |sub|
|
||||
desc "Run the code examples in spec/#{sub}"
|
||||
Spec::Rake::SpecTask.new(sub => spec_prereq) do |t|
|
||||
t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""]
|
||||
t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
|
||||
end
|
||||
end
|
||||
|
||||
desc "Run the code examples in vendor/plugins (except RSpec's own)"
|
||||
Spec::Rake::SpecTask.new(:plugins => spec_prereq) do |t|
|
||||
t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""]
|
||||
t.spec_files = FileList['vendor/plugins/**/spec/**/*_spec.rb'].exclude('vendor/plugins/rspec/*').exclude("vendor/plugins/rspec-rails/*")
|
||||
end
|
||||
|
||||
namespace :plugins do
|
||||
desc "Runs the examples for rspec_on_rails"
|
||||
Spec::Rake::SpecTask.new(:rspec_on_rails) do |t|
|
||||
t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""]
|
||||
t.spec_files = FileList['vendor/plugins/rspec-rails/spec/**/*_spec.rb']
|
||||
end
|
||||
end
|
||||
|
||||
# Setup specs for stats
|
||||
task :statsetup do
|
||||
require 'code_statistics'
|
||||
::STATS_DIRECTORIES << %w(Model\ specs spec/models) if File.exist?('spec/models')
|
||||
::STATS_DIRECTORIES << %w(View\ specs spec/views) if File.exist?('spec/views')
|
||||
::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers) if File.exist?('spec/controllers')
|
||||
::STATS_DIRECTORIES << %w(Helper\ specs spec/helpers) if File.exist?('spec/helpers')
|
||||
::STATS_DIRECTORIES << %w(Library\ specs spec/lib) if File.exist?('spec/lib')
|
||||
::STATS_DIRECTORIES << %w(Routing\ specs spec/routing) if File.exist?('spec/routing')
|
||||
::STATS_DIRECTORIES << %w(Integration\ specs spec/integration) if File.exist?('spec/integration')
|
||||
::CodeStatistics::TEST_TYPES << "Model specs" if File.exist?('spec/models')
|
||||
::CodeStatistics::TEST_TYPES << "View specs" if File.exist?('spec/views')
|
||||
::CodeStatistics::TEST_TYPES << "Controller specs" if File.exist?('spec/controllers')
|
||||
::CodeStatistics::TEST_TYPES << "Helper specs" if File.exist?('spec/helpers')
|
||||
::CodeStatistics::TEST_TYPES << "Library specs" if File.exist?('spec/lib')
|
||||
::CodeStatistics::TEST_TYPES << "Routing specs" if File.exist?('spec/routing')
|
||||
::CodeStatistics::TEST_TYPES << "Integration specs" if File.exist?('spec/integration')
|
||||
end
|
||||
|
||||
namespace :db do
|
||||
namespace :fixtures do
|
||||
desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z."
|
||||
task :load => :environment do
|
||||
ActiveRecord::Base.establish_connection(Rails.env)
|
||||
base_dir = File.join(Rails.root, 'spec', 'fixtures')
|
||||
fixtures_dir = ENV['FIXTURES_DIR'] ? File.join(base_dir, ENV['FIXTURES_DIR']) : base_dir
|
||||
|
||||
require 'active_record/fixtures'
|
||||
(ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/).map {|f| File.join(fixtures_dir, f) } : Dir.glob(File.join(fixtures_dir, '*.{yml,csv}'))).each do |fixture_file|
|
||||
Fixtures.create_fixtures(File.dirname(fixture_file), File.basename(fixture_file, '.*'))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
desc "Initialises the installation, copy the *.tmpl files and directories to versions named without the .tmpl extension. It won't overwrite the files and directories if you've already copied them. You need to manually copy database.yml.tmpl -> database.yml and fill in the details before you run this task."
|
||||
task :setup_tracks => :environment do
|
||||
# Check the root directory for template files
|
||||
FileList["*.tmpl"].each do |template_file|
|
||||
f = File.basename(template_file) # with suffix
|
||||
f_only = File.basename(template_file,".tmpl") # without suffix
|
||||
if File.exists?(f_only)
|
||||
puts f_only + " already exists"
|
||||
else
|
||||
cp_r(f, f_only)
|
||||
puts f_only + " created"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,40 +0,0 @@
|
|||
desc "Updates sqlite/sqlite3 databases created under Tracks 1.03 to the format required for Tracks 1.04. After this is done, you should be able to keep up to date with changes in the schema by running rake db:migrate."
|
||||
task :upgrade_sqlite_db => :environment do
|
||||
# Change the three lines below appropriately for your setup
|
||||
old_db = "tracks_103.db"
|
||||
new_db = "tracks_104.db"
|
||||
cmd = "sqlite3"
|
||||
replace_string = "update todos set done='f' where done=0;\nupdate todos set done='t' where done=1;\nupdate contexts set hide='f' where hide=0;\nupdate contexts set hide='t' where hide=1;\nupdate projects set done='f' where done=0;\nupdate projects set done='t' where done=1;\nCREATE TABLE 'schema_info' (\n 'version' INTEGER default NULL\n);\nINSERT INTO \"schema_info\" VALUES(1);\nCOMMIT;"
|
||||
|
||||
# cd to the db directory
|
||||
cd("db") do
|
||||
# Dump the old db into the temp file and replace the tinyints with booleans
|
||||
`#{cmd} #{old_db} .dump | sed "s/tinyint(4) NOT NULL default '0'/boolean default 'f'/" > temp.sql`
|
||||
# Create a second sqldump file for writing
|
||||
sqldump = File.open("temp2.sql", "w+")
|
||||
File.open("temp.sql") do |file|
|
||||
file.each_line do |line|
|
||||
# If COMMIT is on the line, insert the replace string
|
||||
# else just write the line back in
|
||||
# This effectively replaces COMMIT with the replace string
|
||||
if /COMMIT/ =~ line
|
||||
sqldump.write replace_string
|
||||
else
|
||||
sqldump.write line
|
||||
end
|
||||
end
|
||||
sqldump.close
|
||||
end
|
||||
|
||||
# Read the second dump back in to a new db
|
||||
system "#{cmd} #{new_db} < temp2.sql"
|
||||
puts "Created the a new database called #{new_db}."
|
||||
# Clean up the temp files
|
||||
rm("temp.sql")
|
||||
rm("temp2.sql")
|
||||
puts "Temporary files cleaned up."
|
||||
end
|
||||
|
||||
# rake db:migrate
|
||||
puts "Now check the database and run 'rake db:migrate' in the root of your Tracks installation."
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
module Tracks
|
||||
class Config
|
||||
def self.salt
|
||||
SITE_CONFIG['salt']
|
||||
end
|
||||
|
||||
def self.auth_schemes
|
||||
SITE_CONFIG['authentication_schemes'] || []
|
||||
end
|
||||
|
||||
def self.openid_enabled?
|
||||
auth_schemes.include?('open_id')
|
||||
end
|
||||
|
||||
def self.cas_enabled?
|
||||
auth_schemes.include?('cas')
|
||||
end
|
||||
|
||||
def self.prefered_auth?
|
||||
if SITE_CONFIG['prefered_auth']
|
||||
SITE_CONFIG['prefered_auth']
|
||||
else
|
||||
auth_schemes.first
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,59 +0,0 @@
|
|||
module Tracks
|
||||
module TodoList
|
||||
# TODO: this module should be deprecated. This could mostly (all?) be replaced by named scopes)
|
||||
|
||||
def not_done_todos(opts={})
|
||||
@not_done_todos ||= self.find_not_done_todos(opts)
|
||||
end
|
||||
|
||||
def done_todos
|
||||
@done_todos ||= self.find_done_todos
|
||||
end
|
||||
|
||||
def deferred_todos
|
||||
@deferred_todos ||= self.find_deferred_todos
|
||||
end
|
||||
|
||||
def find_not_done_todos(opts={})
|
||||
with_not_done_scope(opts) do
|
||||
self.todos.find(:all, :order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC")
|
||||
end
|
||||
end
|
||||
|
||||
def find_deferred_todos(opts={})
|
||||
self.todos.find_in_state(:all, :deferred, :order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC")
|
||||
end
|
||||
|
||||
def find_done_todos
|
||||
self.todos.completed.all(:order => "todos.completed_at DESC", :limit => self.user.prefs.show_number_completed)
|
||||
end
|
||||
|
||||
def not_done_todo_count(opts={})
|
||||
with_not_done_scope(opts) do
|
||||
self.todos.count
|
||||
end
|
||||
end
|
||||
|
||||
def with_not_done_scope(opts={})
|
||||
conditions = ["todos.state = ?", 'active']
|
||||
if opts.has_key?(:include_project_hidden_todos) && (opts[:include_project_hidden_todos] == true)
|
||||
conditions = ["(todos.state = ? OR todos.state = ?)", 'active', 'project_hidden']
|
||||
end
|
||||
if opts.has_key?(:tag)
|
||||
conditions = ["todos.state = ? AND taggings.tag_id = ?", 'active', opts[:tag]]
|
||||
end
|
||||
self.todos.send :with_scope, :find => {:conditions => conditions, :include => [:taggings]} do
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
def done_todo_count
|
||||
self.todos.count_in_state(:completed)
|
||||
end
|
||||
|
||||
def deferred_todo_count
|
||||
self.todos.count_in_state(:deferred)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
2
vendor/plugins/extra_validations/init.rb
vendored
2
vendor/plugins/extra_validations/init.rb
vendored
|
@ -1,2 +0,0 @@
|
|||
require 'extra_validations'
|
||||
ActiveRecord::Base.extend ExtraValidations
|
|
@ -1,29 +0,0 @@
|
|||
module ExtraValidations
|
||||
|
||||
# Validates the value of the specified attribute by checking for a forbidden string
|
||||
#
|
||||
# class Person < ActiveRecord::Base
|
||||
# validates_does_not_contain :first_name, :string => ','
|
||||
# end
|
||||
#
|
||||
# A string must be provided or else an exception will be raised.
|
||||
#
|
||||
# Configuration options:
|
||||
# * <tt>message</tt> - A custom error message (default is: "is invalid")
|
||||
# * <tt>string</tt> - The string to verify is not included (note: must be supplied!)
|
||||
# * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update)
|
||||
# * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
||||
# occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
|
||||
# method, proc or string should return or evaluate to a true or false value.
|
||||
def validates_does_not_contain(*attr_names)
|
||||
configuration = { :message => I18n.translate('activerecord.errors.messages')[:invalid], :on => :save, :string => nil }
|
||||
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
|
||||
|
||||
raise(ArgumentError, "A string must be supplied as the :string option of the configuration hash") unless configuration[:string].is_a?(String)
|
||||
|
||||
validates_each(attr_names, configuration) do |record, attr_name, value|
|
||||
record.errors.add(attr_name, configuration[:message]) if value.to_s =~ Regexp.new(Regexp.escape(configuration[:string]))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
35
vendor/plugins/open_id_authentication/CHANGELOG
vendored
35
vendor/plugins/open_id_authentication/CHANGELOG
vendored
|
@ -1,35 +0,0 @@
|
|||
* Fake HTTP method from OpenID server since they only support a GET. Eliminates the need to set an extra route to match the server's reply. [Josh Peek]
|
||||
|
||||
* OpenID 2.0 recommends that forms should use the field name "openid_identifier" rather than "openid_url" [Josh Peek]
|
||||
|
||||
* Return open_id_response.display_identifier to the application instead of .endpoints.claimed_id. [nbibler]
|
||||
|
||||
* Add Timeout protection [Rick]
|
||||
|
||||
* An invalid identity url passed through authenticate_with_open_id will no longer raise an InvalidOpenId exception. Instead it will return Result[:missing] to the completion block.
|
||||
|
||||
* Allow a return_to option to be used instead of the requested url [Josh Peek]
|
||||
|
||||
* Updated plugin to use Ruby OpenID 2.x.x [Josh Peek]
|
||||
|
||||
* Tied plugin to ruby-openid 1.1.4 gem until we can make it compatible with 2.x [DHH]
|
||||
|
||||
* Use URI instead of regexps to normalize the URL and gain free, better matching #8136 [dkubb]
|
||||
|
||||
* Allow -'s in #normalize_url [Rick]
|
||||
|
||||
* remove instance of mattr_accessor, it was breaking tests since they don't load ActiveSupport. Fix Timeout test [Rick]
|
||||
|
||||
* Throw a InvalidOpenId exception instead of just a RuntimeError when the URL can't be normalized [DHH]
|
||||
|
||||
* Just use the path for the return URL, so extra query parameters don't interfere [DHH]
|
||||
|
||||
* Added a new default database-backed store after experiencing trouble with the filestore on NFS. The file store is still available as an option [DHH]
|
||||
|
||||
* Added normalize_url and applied it to all operations going through the plugin [DHH]
|
||||
|
||||
* Removed open_id? as the idea of using the same input box for both OpenID and username has died -- use using_open_id? instead (which checks for the presence of params[:openid_url] by default) [DHH]
|
||||
|
||||
* Added OpenIdAuthentication::Result to make it easier to deal with default situations where you don't care to do something particular for each error state [DHH]
|
||||
|
||||
* Stop relying on root_url being defined, we can just grab the current url instead [DHH]
|
231
vendor/plugins/open_id_authentication/README
vendored
231
vendor/plugins/open_id_authentication/README
vendored
|
@ -1,231 +0,0 @@
|
|||
OpenIdAuthentication
|
||||
====================
|
||||
|
||||
Provides a thin wrapper around the excellent ruby-openid gem from JanRan. Be sure to install that first:
|
||||
|
||||
gem install ruby-openid
|
||||
|
||||
To understand what OpenID is about and how it works, it helps to read the documentation for lib/openid/consumer.rb
|
||||
from that gem.
|
||||
|
||||
The specification used is http://openid.net/specs/openid-authentication-2_0.html.
|
||||
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
|
||||
OpenID authentication uses the session, so be sure that you haven't turned that off. It also relies on a number of
|
||||
database tables to store the authentication keys. So you'll have to run the migration to create these before you get started:
|
||||
|
||||
rake open_id_authentication:db:create
|
||||
|
||||
Or, use the included generators to install or upgrade:
|
||||
|
||||
./script/generate open_id_authentication_tables MigrationName
|
||||
./script/generate upgrade_open_id_authentication_tables MigrationName
|
||||
|
||||
Alternatively, you can use the file-based store, which just relies on on tmp/openids being present in RAILS_ROOT. But be aware that this store only works if you have a single application server. And it's not safe to use across NFS. It's recommended that you use the database store if at all possible. To use the file-based store, you'll also have to add this line to your config/environment.rb:
|
||||
|
||||
OpenIdAuthentication.store = :file
|
||||
|
||||
This particular plugin also relies on the fact that the authentication action allows for both POST and GET operations.
|
||||
If you're using RESTful authentication, you'll need to explicitly allow for this in your routes.rb.
|
||||
|
||||
The plugin also expects to find a root_url method that points to the home page of your site. You can accomplish this by using a root route in config/routes.rb:
|
||||
|
||||
map.root :controller => 'articles'
|
||||
|
||||
This plugin relies on Rails Edge revision 6317 or newer.
|
||||
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
This example is just to meant to demonstrate how you could use OpenID authentication. You might well want to add
|
||||
salted hash logins instead of plain text passwords and other requirements on top of this. Treat it as a starting point,
|
||||
not a destination.
|
||||
|
||||
Note that the User model referenced in the simple example below has an 'identity_url' attribute. You will want to add the same or similar field to whatever
|
||||
model you are using for authentication.
|
||||
|
||||
Also of note is the following code block used in the example below:
|
||||
|
||||
authenticate_with_open_id do |result, identity_url|
|
||||
...
|
||||
end
|
||||
|
||||
In the above code block, 'identity_url' will need to match user.identity_url exactly. 'identity_url' will be a string in the form of 'http://example.com' -
|
||||
If you are storing just 'example.com' with your user, the lookup will fail.
|
||||
|
||||
There is a handy method in this plugin called 'normalize_url' that will help with validating OpenID URLs.
|
||||
|
||||
OpenIdAuthentication.normalize_url(user.identity_url)
|
||||
|
||||
The above will return a standardized version of the OpenID URL - the above called with 'example.com' will return 'http://example.com/'
|
||||
It will also raise an InvalidOpenId exception if the URL is determined to not be valid.
|
||||
Use the above code in your User model and validate OpenID URLs before saving them.
|
||||
|
||||
config/routes.rb
|
||||
|
||||
map.root :controller => 'articles'
|
||||
map.resource :session
|
||||
|
||||
|
||||
app/views/sessions/new.erb
|
||||
|
||||
<% form_tag(session_url) do %>
|
||||
<p>
|
||||
<label for="name">Username:</label>
|
||||
<%= text_field_tag "name" %>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="password">Password:</label>
|
||||
<%= password_field_tag %>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
...or use:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="openid_identifier">OpenID:</label>
|
||||
<%= text_field_tag "openid_identifier" %>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<%= submit_tag 'Sign in', :disable_with => "Signing in…" %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
app/controllers/sessions_controller.rb
|
||||
class SessionsController < ApplicationController
|
||||
def create
|
||||
if using_open_id?
|
||||
open_id_authentication
|
||||
else
|
||||
password_authentication(params[:name], params[:password])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
def password_authentication(name, password)
|
||||
if @current_user = @account.users.authenticate(params[:name], params[:password])
|
||||
successful_login
|
||||
else
|
||||
failed_login "Sorry, that username/password doesn't work"
|
||||
end
|
||||
end
|
||||
|
||||
def open_id_authentication
|
||||
authenticate_with_open_id do |result, identity_url|
|
||||
if result.successful?
|
||||
if @current_user = @account.users.find_by_identity_url(identity_url)
|
||||
successful_login
|
||||
else
|
||||
failed_login "Sorry, no user by that identity URL exists (#{identity_url})"
|
||||
end
|
||||
else
|
||||
failed_login result.message
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def successful_login
|
||||
session[:user_id] = @current_user.id
|
||||
redirect_to(root_url)
|
||||
end
|
||||
|
||||
def failed_login(message)
|
||||
flash[:error] = message
|
||||
redirect_to(new_session_url)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
If you're fine with the result messages above and don't need individual logic on a per-failure basis,
|
||||
you can collapse the case into a mere boolean:
|
||||
|
||||
def open_id_authentication
|
||||
authenticate_with_open_id do |result, identity_url|
|
||||
if result.successful? && @current_user = @account.users.find_by_identity_url(identity_url)
|
||||
successful_login
|
||||
else
|
||||
failed_login(result.message || "Sorry, no user by that identity URL exists (#{identity_url})")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Simple Registration OpenID Extension
|
||||
====================================
|
||||
|
||||
Some OpenID Providers support this lightweight profile exchange protocol. See more: http://www.openidenabled.com/openid/simple-registration-extension
|
||||
|
||||
You can support it in your app by changing #open_id_authentication
|
||||
|
||||
def open_id_authentication(identity_url)
|
||||
# Pass optional :required and :optional keys to specify what sreg fields you want.
|
||||
# Be sure to yield registration, a third argument in the #authenticate_with_open_id block.
|
||||
authenticate_with_open_id(identity_url,
|
||||
:required => [ :nickname, :email ],
|
||||
:optional => :fullname) do |result, identity_url, registration|
|
||||
case result.status
|
||||
when :missing
|
||||
failed_login "Sorry, the OpenID server couldn't be found"
|
||||
when :invalid
|
||||
failed_login "Sorry, but this does not appear to be a valid OpenID"
|
||||
when :canceled
|
||||
failed_login "OpenID verification was canceled"
|
||||
when :failed
|
||||
failed_login "Sorry, the OpenID verification failed"
|
||||
when :successful
|
||||
if @current_user = @account.users.find_by_identity_url(identity_url)
|
||||
assign_registration_attributes!(registration)
|
||||
|
||||
if current_user.save
|
||||
successful_login
|
||||
else
|
||||
failed_login "Your OpenID profile registration failed: " +
|
||||
@current_user.errors.full_messages.to_sentence
|
||||
end
|
||||
else
|
||||
failed_login "Sorry, no user by that identity URL exists"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# registration is a hash containing the valid sreg keys given above
|
||||
# use this to map them to fields of your user model
|
||||
def assign_registration_attributes!(registration)
|
||||
model_to_registration_mapping.each do |model_attribute, registration_attribute|
|
||||
unless registration[registration_attribute].blank?
|
||||
@current_user.send("#{model_attribute}=", registration[registration_attribute])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def model_to_registration_mapping
|
||||
{ :login => 'nickname', :email => 'email', :display_name => 'fullname' }
|
||||
end
|
||||
|
||||
Attribute Exchange OpenID Extension
|
||||
===================================
|
||||
|
||||
Some OpenID providers also support the OpenID AX (attribute exchange) protocol for exchanging identity information between endpoints. See more: http://openid.net/specs/openid-attribute-exchange-1_0.html
|
||||
|
||||
Accessing AX data is very similar to the Simple Registration process, described above -- just add the URI identifier for the AX field to your :optional or :required parameters. For example:
|
||||
|
||||
authenticate_with_open_id(identity_url,
|
||||
:required => [ :email, 'http://schema.openid.net/birthDate' ]) do |result, identity_url, registration|
|
||||
|
||||
This would provide the sreg data for :email, and the AX data for 'http://schema.openid.net/birthDate'
|
||||
|
||||
|
||||
|
||||
Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license
|
22
vendor/plugins/open_id_authentication/Rakefile
vendored
22
vendor/plugins/open_id_authentication/Rakefile
vendored
|
@ -1,22 +0,0 @@
|
|||
require 'rake'
|
||||
require 'rake/testtask'
|
||||
require 'rake/rdoctask'
|
||||
|
||||
desc 'Default: run unit tests.'
|
||||
task :default => :test
|
||||
|
||||
desc 'Test the open_id_authentication plugin.'
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.libs << 'lib'
|
||||
t.pattern = 'test/**/*_test.rb'
|
||||
t.verbose = true
|
||||
end
|
||||
|
||||
desc 'Generate documentation for the open_id_authentication plugin.'
|
||||
Rake::RDocTask.new(:rdoc) do |rdoc|
|
||||
rdoc.rdoc_dir = 'rdoc'
|
||||
rdoc.title = 'OpenIdAuthentication'
|
||||
rdoc.options << '--line-numbers' << '--inline-source'
|
||||
rdoc.rdoc_files.include('README')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
end
|
|
@ -1,11 +0,0 @@
|
|||
class OpenIdAuthenticationTablesGenerator < Rails::Generator::NamedBase
|
||||
def initialize(runtime_args, runtime_options = {})
|
||||
super
|
||||
end
|
||||
|
||||
def manifest
|
||||
record do |m|
|
||||
m.migration_template 'migration.rb', 'db/migrate'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,20 +0,0 @@
|
|||
class <%= class_name %> < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :open_id_authentication_associations, :force => true do |t|
|
||||
t.integer :issued, :lifetime
|
||||
t.string :handle, :assoc_type
|
||||
t.binary :server_url, :secret
|
||||
end
|
||||
|
||||
create_table :open_id_authentication_nonces, :force => true do |t|
|
||||
t.integer :timestamp, :null => false
|
||||
t.string :server_url, :null => true
|
||||
t.string :salt, :null => false
|
||||
end
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :open_id_authentication_associations
|
||||
drop_table :open_id_authentication_nonces
|
||||
end
|
||||
end
|
|
@ -1,26 +0,0 @@
|
|||
class <%= class_name %> < ActiveRecord::Migration
|
||||
def self.up
|
||||
drop_table :open_id_authentication_settings
|
||||
drop_table :open_id_authentication_nonces
|
||||
|
||||
create_table :open_id_authentication_nonces, :force => true do |t|
|
||||
t.integer :timestamp, :null => false
|
||||
t.string :server_url, :null => true
|
||||
t.string :salt, :null => false
|
||||
end
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :open_id_authentication_nonces
|
||||
|
||||
create_table :open_id_authentication_nonces, :force => true do |t|
|
||||
t.integer :created
|
||||
t.string :nonce
|
||||
end
|
||||
|
||||
create_table :open_id_authentication_settings, :force => true do |t|
|
||||
t.string :setting
|
||||
t.binary :value
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,11 +0,0 @@
|
|||
class UpgradeOpenIdAuthenticationTablesGenerator < Rails::Generator::NamedBase
|
||||
def initialize(runtime_args, runtime_options = {})
|
||||
super
|
||||
end
|
||||
|
||||
def manifest
|
||||
record do |m|
|
||||
m.migration_template 'migration.rb', 'db/migrate'
|
||||
end
|
||||
end
|
||||
end
|
18
vendor/plugins/open_id_authentication/init.rb
vendored
18
vendor/plugins/open_id_authentication/init.rb
vendored
|
@ -1,18 +0,0 @@
|
|||
if config.respond_to?(:gems)
|
||||
config.gem 'ruby-openid', :lib => 'openid', :version => '>=2.0.4'
|
||||
else
|
||||
begin
|
||||
require 'openid'
|
||||
rescue LoadError
|
||||
begin
|
||||
gem 'ruby-openid', '>=2.0.4'
|
||||
rescue Gem::LoadError
|
||||
puts "Install the ruby-openid gem to enable OpenID support"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
config.to_prepare do
|
||||
OpenID::Util.logger = Rails.logger
|
||||
ActionController::Base.send :include, OpenIdAuthentication
|
||||
end
|
|
@ -1,240 +0,0 @@
|
|||
require 'uri'
|
||||
require 'openid/extensions/sreg'
|
||||
require 'openid/extensions/ax'
|
||||
require 'openid/store/filesystem'
|
||||
|
||||
require File.dirname(__FILE__) + '/open_id_authentication/association'
|
||||
require File.dirname(__FILE__) + '/open_id_authentication/nonce'
|
||||
require File.dirname(__FILE__) + '/open_id_authentication/db_store'
|
||||
require File.dirname(__FILE__) + '/open_id_authentication/request'
|
||||
require File.dirname(__FILE__) + '/open_id_authentication/timeout_fixes' if OpenID::VERSION == "2.0.4"
|
||||
|
||||
module OpenIdAuthentication
|
||||
OPEN_ID_AUTHENTICATION_DIR = RAILS_ROOT + "/tmp/openids"
|
||||
|
||||
def self.store
|
||||
@@store
|
||||
end
|
||||
|
||||
def self.store=(*store_option)
|
||||
store, *parameters = *([ store_option ].flatten)
|
||||
|
||||
@@store = case store
|
||||
when :db
|
||||
OpenIdAuthentication::DbStore.new
|
||||
when :file
|
||||
OpenID::Store::Filesystem.new(OPEN_ID_AUTHENTICATION_DIR)
|
||||
else
|
||||
store
|
||||
end
|
||||
end
|
||||
|
||||
self.store = :db
|
||||
|
||||
class InvalidOpenId < StandardError
|
||||
end
|
||||
|
||||
class Result
|
||||
ERROR_MESSAGES = {
|
||||
:missing => "Sorry, the OpenID server couldn't be found",
|
||||
:invalid => "Sorry, but this does not appear to be a valid OpenID",
|
||||
:canceled => "OpenID verification was canceled",
|
||||
:failed => "OpenID verification failed",
|
||||
:setup_needed => "OpenID verification needs setup"
|
||||
}
|
||||
|
||||
def self.[](code)
|
||||
new(code)
|
||||
end
|
||||
|
||||
def initialize(code)
|
||||
@code = code
|
||||
end
|
||||
|
||||
def status
|
||||
@code
|
||||
end
|
||||
|
||||
ERROR_MESSAGES.keys.each { |state| define_method("#{state}?") { @code == state } }
|
||||
|
||||
def successful?
|
||||
@code == :successful
|
||||
end
|
||||
|
||||
def unsuccessful?
|
||||
ERROR_MESSAGES.keys.include?(@code)
|
||||
end
|
||||
|
||||
def message
|
||||
ERROR_MESSAGES[@code]
|
||||
end
|
||||
end
|
||||
|
||||
# normalizes an OpenID according to http://openid.net/specs/openid-authentication-2_0.html#normalization
|
||||
def self.normalize_identifier(identifier)
|
||||
# clean up whitespace
|
||||
identifier = identifier.to_s.strip
|
||||
|
||||
# if an XRI has a prefix, strip it.
|
||||
identifier.gsub!(/xri:\/\//i, '')
|
||||
|
||||
# dodge XRIs -- TODO: validate, don't just skip.
|
||||
unless ['=', '@', '+', '$', '!', '('].include?(identifier.at(0))
|
||||
# does it begin with http? if not, add it.
|
||||
identifier = "http://#{identifier}" unless identifier =~ /^http/i
|
||||
|
||||
# strip any fragments
|
||||
identifier.gsub!(/\#(.*)$/, '')
|
||||
|
||||
begin
|
||||
uri = URI.parse(identifier)
|
||||
uri.scheme = uri.scheme.downcase # URI should do this
|
||||
identifier = uri.normalize.to_s
|
||||
rescue URI::InvalidURIError
|
||||
raise InvalidOpenId.new("#{identifier} is not an OpenID identifier")
|
||||
end
|
||||
end
|
||||
|
||||
return identifier
|
||||
end
|
||||
|
||||
# deprecated for OpenID 2.0, where not all OpenIDs are URLs
|
||||
def self.normalize_url(url)
|
||||
ActiveSupport::Deprecation.warn "normalize_url has been deprecated, use normalize_identifier instead"
|
||||
self.normalize_identifier(url)
|
||||
end
|
||||
|
||||
protected
|
||||
def normalize_url(url)
|
||||
OpenIdAuthentication.normalize_url(url)
|
||||
end
|
||||
|
||||
def normalize_identifier(url)
|
||||
OpenIdAuthentication.normalize_identifier(url)
|
||||
end
|
||||
|
||||
# The parameter name of "openid_identifier" is used rather than the Rails convention "open_id_identifier"
|
||||
# because that's what the specification dictates in order to get browser auto-complete working across sites
|
||||
def using_open_id?(identity_url = nil) #:doc:
|
||||
identity_url ||= params[:openid_identifier] || params[:openid_url]
|
||||
!identity_url.blank? || params[:open_id_complete]
|
||||
end
|
||||
|
||||
def authenticate_with_open_id(identity_url = nil, options = {}, &block) #:doc:
|
||||
identity_url ||= params[:openid_identifier] || params[:openid_url]
|
||||
|
||||
if params[:open_id_complete].nil?
|
||||
begin_open_id_authentication(identity_url, options, &block)
|
||||
else
|
||||
complete_open_id_authentication(&block)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def begin_open_id_authentication(identity_url, options = {})
|
||||
identity_url = normalize_identifier(identity_url)
|
||||
return_to = options.delete(:return_to)
|
||||
method = options.delete(:method)
|
||||
|
||||
options[:required] ||= [] # reduces validation later
|
||||
options[:optional] ||= []
|
||||
|
||||
open_id_request = open_id_consumer.begin(identity_url)
|
||||
add_simple_registration_fields(open_id_request, options)
|
||||
add_ax_fields(open_id_request, options)
|
||||
redirect_to(open_id_redirect_url(open_id_request, return_to, method))
|
||||
rescue OpenIdAuthentication::InvalidOpenId => e
|
||||
yield Result[:invalid], identity_url, nil
|
||||
rescue OpenID::OpenIDError, Timeout::Error => e
|
||||
logger.error("[OPENID] #{e}")
|
||||
yield Result[:missing], identity_url, nil
|
||||
end
|
||||
|
||||
def complete_open_id_authentication
|
||||
params_with_path = params.reject { |key, value| request.path_parameters[key] }
|
||||
params_with_path.delete(:format)
|
||||
open_id_response = timeout_protection_from_identity_server { open_id_consumer.complete(params_with_path, requested_url) }
|
||||
identity_url = normalize_identifier(open_id_response.display_identifier) if open_id_response.display_identifier
|
||||
|
||||
case open_id_response.status
|
||||
when OpenID::Consumer::SUCCESS
|
||||
profile_data = {}
|
||||
|
||||
# merge the SReg data and the AX data into a single hash of profile data
|
||||
[ OpenID::SReg::Response, OpenID::AX::FetchResponse ].each do |data_response|
|
||||
if data_response.from_success_response( open_id_response )
|
||||
profile_data.merge! data_response.from_success_response( open_id_response ).data
|
||||
end
|
||||
end
|
||||
|
||||
yield Result[:successful], identity_url, profile_data
|
||||
when OpenID::Consumer::CANCEL
|
||||
yield Result[:canceled], identity_url, nil
|
||||
when OpenID::Consumer::FAILURE
|
||||
yield Result[:failed], identity_url, nil
|
||||
when OpenID::Consumer::SETUP_NEEDED
|
||||
yield Result[:setup_needed], open_id_response.setup_url, nil
|
||||
end
|
||||
end
|
||||
|
||||
def open_id_consumer
|
||||
OpenID::Consumer.new(session, OpenIdAuthentication.store)
|
||||
end
|
||||
|
||||
def add_simple_registration_fields(open_id_request, fields)
|
||||
sreg_request = OpenID::SReg::Request.new
|
||||
|
||||
# filter out AX identifiers (URIs)
|
||||
required_fields = fields[:required].collect { |f| f.to_s unless f =~ /^https?:\/\// }.compact
|
||||
optional_fields = fields[:optional].collect { |f| f.to_s unless f =~ /^https?:\/\// }.compact
|
||||
|
||||
sreg_request.request_fields(required_fields, true) unless required_fields.blank?
|
||||
sreg_request.request_fields(optional_fields, false) unless optional_fields.blank?
|
||||
sreg_request.policy_url = fields[:policy_url] if fields[:policy_url]
|
||||
open_id_request.add_extension(sreg_request)
|
||||
end
|
||||
|
||||
def add_ax_fields( open_id_request, fields )
|
||||
ax_request = OpenID::AX::FetchRequest.new
|
||||
|
||||
# look through the :required and :optional fields for URIs (AX identifiers)
|
||||
fields[:required].each do |f|
|
||||
next unless f =~ /^https?:\/\//
|
||||
ax_request.add( OpenID::AX::AttrInfo.new( f, nil, true ) )
|
||||
end
|
||||
|
||||
fields[:optional].each do |f|
|
||||
next unless f =~ /^https?:\/\//
|
||||
ax_request.add( OpenID::AX::AttrInfo.new( f, nil, false ) )
|
||||
end
|
||||
|
||||
open_id_request.add_extension( ax_request )
|
||||
end
|
||||
|
||||
def open_id_redirect_url(open_id_request, return_to = nil, method = nil)
|
||||
open_id_request.return_to_args['_method'] = (method || request.method).to_s
|
||||
open_id_request.return_to_args['open_id_complete'] = '1'
|
||||
open_id_request.redirect_url(root_url, return_to || requested_url)
|
||||
end
|
||||
|
||||
def requested_url
|
||||
relative_url_root = self.class.respond_to?(:relative_url_root) ?
|
||||
self.class.relative_url_root.to_s :
|
||||
request.relative_url_root
|
||||
"#{request.protocol}#{request.host_with_port}#{ActionController::Base.relative_url_root}#{request.path}"
|
||||
end
|
||||
|
||||
def timeout_protection_from_identity_server
|
||||
yield
|
||||
rescue Timeout::Error
|
||||
Class.new do
|
||||
def status
|
||||
OpenID::FAILURE
|
||||
end
|
||||
|
||||
def msg
|
||||
"Identity server timed out"
|
||||
end
|
||||
end.new
|
||||
end
|
||||
end
|
|
@ -1,9 +0,0 @@
|
|||
module OpenIdAuthentication
|
||||
class Association < ActiveRecord::Base
|
||||
set_table_name :open_id_authentication_associations
|
||||
|
||||
def from_record
|
||||
OpenID::Association.new(handle, secret, issued, lifetime, assoc_type)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,55 +0,0 @@
|
|||
require 'openid/store/interface'
|
||||
|
||||
module OpenIdAuthentication
|
||||
class DbStore < OpenID::Store::Interface
|
||||
def self.cleanup_nonces
|
||||
now = Time.now.to_i
|
||||
Nonce.delete_all(["timestamp > ? OR timestamp < ?", now + OpenID::Nonce.skew, now - OpenID::Nonce.skew])
|
||||
end
|
||||
|
||||
def self.cleanup_associations
|
||||
now = Time.now.to_i
|
||||
Association.delete_all(['issued + lifetime > ?',now])
|
||||
end
|
||||
|
||||
def store_association(server_url, assoc)
|
||||
remove_association(server_url, assoc.handle)
|
||||
Association.create(:server_url => server_url,
|
||||
:handle => assoc.handle,
|
||||
:secret => assoc.secret,
|
||||
:issued => assoc.issued,
|
||||
:lifetime => assoc.lifetime,
|
||||
:assoc_type => assoc.assoc_type)
|
||||
end
|
||||
|
||||
def get_association(server_url, handle = nil)
|
||||
assocs = if handle.blank?
|
||||
Association.find_all_by_server_url(server_url)
|
||||
else
|
||||
Association.find_all_by_server_url_and_handle(server_url, handle)
|
||||
end
|
||||
|
||||
assocs.reverse.each do |assoc|
|
||||
a = assoc.from_record
|
||||
if a.expires_in == 0
|
||||
assoc.destroy
|
||||
else
|
||||
return a
|
||||
end
|
||||
end if assocs.any?
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
def remove_association(server_url, handle)
|
||||
Association.delete_all(['server_url = ? AND handle = ?', server_url, handle]) > 0
|
||||
end
|
||||
|
||||
def use_nonce(server_url, timestamp, salt)
|
||||
return false if Nonce.find_by_server_url_and_timestamp_and_salt(server_url, timestamp, salt)
|
||||
return false if (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew
|
||||
Nonce.create(:server_url => server_url, :timestamp => timestamp, :salt => salt)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,5 +0,0 @@
|
|||
module OpenIdAuthentication
|
||||
class Nonce < ActiveRecord::Base
|
||||
set_table_name :open_id_authentication_nonces
|
||||
end
|
||||
end
|
|
@ -1,23 +0,0 @@
|
|||
module OpenIdAuthentication
|
||||
module Request
|
||||
def self.included(base)
|
||||
base.alias_method_chain :request_method, :openid
|
||||
end
|
||||
|
||||
def request_method_with_openid
|
||||
if !parameters[:_method].blank? && parameters[:open_id_complete] == '1'
|
||||
parameters[:_method].to_sym
|
||||
else
|
||||
request_method_without_openid
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# In Rails 2.3, the request object has been renamed
|
||||
# from AbstractRequest to Request
|
||||
if defined? ActionController::Request
|
||||
ActionController::Request.send :include, OpenIdAuthentication::Request
|
||||
else
|
||||
ActionController::AbstractRequest.send :include, OpenIdAuthentication::Request
|
||||
end
|
|
@ -1,20 +0,0 @@
|
|||
# http://trac.openidenabled.com/trac/ticket/156
|
||||
module OpenID
|
||||
@@timeout_threshold = 20
|
||||
|
||||
def self.timeout_threshold
|
||||
@@timeout_threshold
|
||||
end
|
||||
|
||||
def self.timeout_threshold=(value)
|
||||
@@timeout_threshold = value
|
||||
end
|
||||
|
||||
class StandardFetcher
|
||||
def make_http(uri)
|
||||
http = @proxy.new(uri.host, uri.port)
|
||||
http.read_timeout = http.open_timeout = OpenID.timeout_threshold
|
||||
http
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,30 +0,0 @@
|
|||
namespace :open_id_authentication do
|
||||
namespace :db do
|
||||
desc "Creates authentication tables for use with OpenIdAuthentication"
|
||||
task :create => :environment do
|
||||
generate_migration(["open_id_authentication_tables", "add_open_id_authentication_tables"])
|
||||
end
|
||||
|
||||
desc "Upgrade authentication tables from ruby-openid 1.x.x to 2.x.x"
|
||||
task :upgrade => :environment do
|
||||
generate_migration(["upgrade_open_id_authentication_tables", "upgrade_open_id_authentication_tables"])
|
||||
end
|
||||
|
||||
def generate_migration(args)
|
||||
require 'rails_generator'
|
||||
require 'rails_generator/scripts/generate'
|
||||
|
||||
if ActiveRecord::Base.connection.supports_migrations?
|
||||
Rails::Generator::Scripts::Generate.new.run(args)
|
||||
else
|
||||
raise "Task unavailable to this database (no migration support)"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Clear the authentication tables"
|
||||
task :clear => :environment do
|
||||
OpenIdAuthentication::DbStore.cleanup_nonces
|
||||
OpenIdAuthentication::DbStore.cleanup_associations
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,32 +0,0 @@
|
|||
require File.dirname(__FILE__) + '/test_helper'
|
||||
|
||||
class NormalizeTest < Test::Unit::TestCase
|
||||
include OpenIdAuthentication
|
||||
|
||||
NORMALIZATIONS = {
|
||||
"openid.aol.com/nextangler" => "http://openid.aol.com/nextangler",
|
||||
"http://openid.aol.com/nextangler" => "http://openid.aol.com/nextangler",
|
||||
"https://openid.aol.com/nextangler" => "https://openid.aol.com/nextangler",
|
||||
"HTTP://OPENID.AOL.COM/NEXTANGLER" => "http://openid.aol.com/NEXTANGLER",
|
||||
"HTTPS://OPENID.AOL.COM/NEXTANGLER" => "https://openid.aol.com/NEXTANGLER",
|
||||
"loudthinking.com" => "http://loudthinking.com/",
|
||||
"http://loudthinking.com" => "http://loudthinking.com/",
|
||||
"http://loudthinking.com:80" => "http://loudthinking.com/",
|
||||
"https://loudthinking.com:443" => "https://loudthinking.com/",
|
||||
"http://loudthinking.com:8080" => "http://loudthinking.com:8080/",
|
||||
"techno-weenie.net" => "http://techno-weenie.net/",
|
||||
"http://techno-weenie.net" => "http://techno-weenie.net/",
|
||||
"http://techno-weenie.net " => "http://techno-weenie.net/",
|
||||
"=name" => "=name"
|
||||
}
|
||||
|
||||
def test_normalizations
|
||||
NORMALIZATIONS.each do |from, to|
|
||||
assert_equal to, normalize_identifier(from)
|
||||
end
|
||||
end
|
||||
|
||||
def test_broken_open_id
|
||||
assert_raises(InvalidOpenId) { normalize_identifier(nil) }
|
||||
end
|
||||
end
|
|
@ -1,46 +0,0 @@
|
|||
require File.dirname(__FILE__) + '/test_helper'
|
||||
|
||||
class OpenIdAuthenticationTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@controller = Class.new do
|
||||
include OpenIdAuthentication
|
||||
def params() {} end
|
||||
end.new
|
||||
end
|
||||
|
||||
def test_authentication_should_fail_when_the_identity_server_is_missing
|
||||
open_id_consumer = mock()
|
||||
open_id_consumer.expects(:begin).raises(OpenID::OpenIDError)
|
||||
@controller.expects(:open_id_consumer).returns(open_id_consumer)
|
||||
@controller.expects(:logger).returns(mock(:error => true))
|
||||
|
||||
@controller.send(:authenticate_with_open_id, "http://someone.example.com") do |result, identity_url|
|
||||
assert result.missing?
|
||||
assert_equal "Sorry, the OpenID server couldn't be found", result.message
|
||||
end
|
||||
end
|
||||
|
||||
def test_authentication_should_be_invalid_when_the_identity_url_is_invalid
|
||||
@controller.send(:authenticate_with_open_id, "!") do |result, identity_url|
|
||||
assert result.invalid?, "Result expected to be invalid but was not"
|
||||
assert_equal "Sorry, but this does not appear to be a valid OpenID", result.message
|
||||
end
|
||||
end
|
||||
|
||||
def test_authentication_should_fail_when_the_identity_server_times_out
|
||||
open_id_consumer = mock()
|
||||
open_id_consumer.expects(:begin).raises(Timeout::Error, "Identity Server took too long.")
|
||||
@controller.expects(:open_id_consumer).returns(open_id_consumer)
|
||||
@controller.expects(:logger).returns(mock(:error => true))
|
||||
|
||||
@controller.send(:authenticate_with_open_id, "http://someone.example.com") do |result, identity_url|
|
||||
assert result.missing?
|
||||
assert_equal "Sorry, the OpenID server couldn't be found", result.message
|
||||
end
|
||||
end
|
||||
|
||||
def test_authentication_should_begin_when_the_identity_server_is_present
|
||||
@controller.expects(:begin_open_id_authentication)
|
||||
@controller.send(:authenticate_with_open_id, "http://someone.example.com")
|
||||
end
|
||||
end
|
|
@ -1,14 +0,0 @@
|
|||
require File.dirname(__FILE__) + '/test_helper'
|
||||
|
||||
class StatusTest < Test::Unit::TestCase
|
||||
include OpenIdAuthentication
|
||||
|
||||
def test_state_conditional
|
||||
assert Result[:missing].missing?
|
||||
assert Result[:missing].unsuccessful?
|
||||
assert !Result[:missing].successful?
|
||||
|
||||
assert Result[:successful].successful?
|
||||
assert !Result[:successful].unsuccessful?
|
||||
end
|
||||
end
|
|
@ -1,17 +0,0 @@
|
|||
require 'test/unit'
|
||||
require 'rubygems'
|
||||
|
||||
gem 'activesupport'
|
||||
require 'active_support'
|
||||
|
||||
gem 'actionpack'
|
||||
require 'action_controller'
|
||||
|
||||
gem 'mocha'
|
||||
require 'mocha'
|
||||
|
||||
gem 'ruby-openid'
|
||||
require 'openid'
|
||||
|
||||
RAILS_ROOT = File.dirname(__FILE__) unless defined? RAILS_ROOT
|
||||
require File.dirname(__FILE__) + "/../lib/open_id_authentication"
|
7
vendor/plugins/resource_feeder/README
vendored
7
vendor/plugins/resource_feeder/README
vendored
|
@ -1,7 +0,0 @@
|
|||
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
vendor/plugins/resource_feeder/Rakefile
vendored
22
vendor/plugins/resource_feeder/Rakefile
vendored
|
@ -1,22 +0,0 @@
|
|||
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
vendor/plugins/resource_feeder/init.rb
vendored
2
vendor/plugins/resource_feeder/init.rb
vendored
|
@ -1,2 +0,0 @@
|
|||
require 'resource_feeder'
|
||||
ActionController::Base.send(:include, ResourceFeeder::Rss, ResourceFeeder::Atom)
|
|
@ -1,2 +0,0 @@
|
|||
require 'resource_feeder/rss'
|
||||
require 'resource_feeder/atom'
|
|
@ -1,67 +0,0 @@
|
|||
require 'resource_feeder/common'
|
||||
|
||||
module ResourceFeeder
|
||||
module Atom
|
||||
include ResourceFeeder::Common
|
||||
include ActionController::Routing
|
||||
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] ||= polymorphic_url(new_record, :controller => options[:url_writer].controller_name)
|
||||
|
||||
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| polymorphic_url(r, :controller => options[:url_writer].controller_name) }
|
||||
|
||||
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
|
||||
end
|
||||
end
|
|
@ -1,24 +0,0 @@
|
|||
module ResourceFeeder
|
||||
module Common
|
||||
private
|
||||
def call_or_read(procedure_or_attributes, resource)
|
||||
case procedure_or_attributes
|
||||
when nil
|
||||
raise ArgumentError, "WTF is nil here? #{resource.inspect}"
|
||||
when Array
|
||||
attributes = procedure_or_attributes
|
||||
if attr = attributes.select { |a| resource.respond_to?(a) }.first
|
||||
resource.send attr
|
||||
end
|
||||
when Symbol
|
||||
attribute = procedure_or_attributes
|
||||
resource.send(attribute)
|
||||
when Proc
|
||||
procedure = procedure_or_attributes
|
||||
procedure.call(resource)
|
||||
else
|
||||
raise ArgumentError, "WTF is #{procedure_or_attributes.inspect} here? #{resource.inspect}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,68 +0,0 @@
|
|||
require 'resource_feeder/common'
|
||||
|
||||
module ResourceFeeder
|
||||
module Rss
|
||||
include ResourceFeeder::Common
|
||||
include ActionController::Routing
|
||||
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] ||= polymorphic_url(new_record, :controller => options[:url_writer].controller_name)
|
||||
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| polymorphic_url(r, :controller => options[:url_writer].controller_name) }
|
||||
|
||||
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
|
||||
end
|
||||
end
|
|
@ -1,85 +0,0 @@
|
|||
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
|
|
@ -1,86 +0,0 @@
|
|||
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
|
|
@ -1,64 +0,0 @@
|
|||
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
|
|
@ -1,5 +0,0 @@
|
|||
SimpleLdapAuthenticator
|
||||
=======================
|
||||
|
||||
Allows for simple authentication to an LDAP server with a minimum of
|
||||
configuration. See the RDoc for details.
|
|
@ -1,22 +0,0 @@
|
|||
require 'rake'
|
||||
require 'rake/testtask'
|
||||
require 'rake/rdoctask'
|
||||
|
||||
desc 'Default: run unit tests.'
|
||||
task :default => :test
|
||||
|
||||
desc 'Test the simple_ldap_authenticator plugin.'
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.libs << 'lib'
|
||||
t.pattern = 'test/**/*_test.rb'
|
||||
t.verbose = true
|
||||
end
|
||||
|
||||
desc 'Generate documentation for the simple_ldap_authenticator plugin.'
|
||||
Rake::RDocTask.new(:rdoc) do |rdoc|
|
||||
rdoc.rdoc_dir = 'rdoc'
|
||||
rdoc.title = 'SimpleLdapAuthenticator'
|
||||
rdoc.options << '--line-numbers' << '--inline-source'
|
||||
rdoc.rdoc_files.include('README')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
# Include hook code here
|
||||
#require 'simple_ldap_authenticator'
|
|
@ -1 +0,0 @@
|
|||
# Install hook code here
|
|
@ -1,127 +0,0 @@
|
|||
# SimpleLdapAuthenticator
|
||||
#
|
||||
# This plugin supports both Ruby/LDAP and Net::LDAP, defaulting to Ruby/LDAP
|
||||
# if it is available. If both are installed and you want to force the use of
|
||||
# Net::LDAP, set SimpleLdapAuthenticator.ldap_library = 'net/ldap'.
|
||||
|
||||
# Allows for easily authenticating users via LDAP (or LDAPS). If authenticating
|
||||
# via LDAP to a server running on localhost, you should only have to configure
|
||||
# the login_format.
|
||||
#
|
||||
# Can be configured using the following accessors (with examples):
|
||||
# * login_format = '%s@domain.com' # Active Directory, OR
|
||||
# * login_format = 'cn=%s,cn=users,o=organization,c=us' # Other LDAP servers
|
||||
# * servers = ['dc1.domain.com', 'dc2.domain.com'] # names/addresses of LDAP servers to use
|
||||
# * use_ssl = true # for logging in via LDAPS
|
||||
# * port = 3289 # instead of 389 for LDAP or 636 for LDAPS
|
||||
# * logger = RAILS_DEFAULT_LOGGER # for logging authentication successes/failures
|
||||
#
|
||||
# The class is used as a global variable, you are not supposed to create an
|
||||
# instance of it. For example:
|
||||
#
|
||||
# require 'simple_ldap_authenticator'
|
||||
# SimpleLdapAuthenticator.servers = %w'dc1.domain.com dc2.domain.com'
|
||||
# SimpleLdapAuthenticator.use_ssl = true
|
||||
# SimpleLdapAuthenticator.login_format = '%s@domain.com'
|
||||
# SimpleLdapAuthenticator.logger = RAILS_DEFAULT_LOGGER
|
||||
# class LoginController < ApplicationController
|
||||
# def login
|
||||
# return redirect_to(:action=>'try_again') unless SimpleLdapAuthenticator.valid?(params[:username], params[:password])
|
||||
# session[:username] = params[:username]
|
||||
# end
|
||||
# end
|
||||
class SimpleLdapAuthenticator
|
||||
class << self
|
||||
@servers = ['127.0.0.1']
|
||||
@use_ssl = false
|
||||
@login_format = '%s'
|
||||
attr_accessor :servers, :use_ssl, :port, :login_format, :logger, :connection, :ldap_library
|
||||
|
||||
# Load the required LDAP library, either 'ldap' or 'net/ldap'
|
||||
def load_ldap_library
|
||||
return if @ldap_library_loaded
|
||||
if ldap_library
|
||||
if ldap_library == 'net/ldap'
|
||||
require 'net/ldap'
|
||||
else
|
||||
require 'ldap'
|
||||
require 'ldap/control'
|
||||
end
|
||||
else
|
||||
begin
|
||||
require 'ldap'
|
||||
require 'ldap/control'
|
||||
ldap_library = 'ldap'
|
||||
rescue LoadError
|
||||
require 'net/ldap'
|
||||
ldap_library = 'net/ldap'
|
||||
end
|
||||
end
|
||||
@ldap_library_loaded = true
|
||||
end
|
||||
|
||||
# The next LDAP server to which to connect
|
||||
def server
|
||||
servers[0]
|
||||
end
|
||||
|
||||
# The connection to the LDAP server. A single connection is made and the
|
||||
# connection is only changed if a server returns an error other than
|
||||
# invalid password.
|
||||
def connection
|
||||
return @connection if @connection
|
||||
load_ldap_library
|
||||
@connection = if ldap_library == 'net/ldap'
|
||||
Net::LDAP.new(:host=>server, :port=>(port), :encryption=>(:simple_tls if use_ssl))
|
||||
else
|
||||
(use_ssl ? LDAP::SSLConn : LDAP::Conn).new(server, port)
|
||||
end
|
||||
end
|
||||
|
||||
# The port to use. Defaults to 389 for LDAP and 636 for LDAPS.
|
||||
def port
|
||||
@port ||= use_ssl ? 636 : 389
|
||||
end
|
||||
|
||||
# Disconnect from current LDAP server and use a different LDAP server on the
|
||||
# next authentication attempt
|
||||
def switch_server
|
||||
self.connection = nil
|
||||
servers << servers.shift
|
||||
end
|
||||
|
||||
# Check the validity of a login/password combination
|
||||
def valid?(login, password)
|
||||
if ldap_library == 'net/ldap'
|
||||
connection.authenticate(login_format % login.to_s, password.to_s)
|
||||
begin
|
||||
if connection.bind
|
||||
logger.info("Authenticated #{login.to_s} by #{server}") if logger
|
||||
true
|
||||
else
|
||||
logger.info("Error attempting to authenticate #{login.to_s} by #{server}: #{connection.get_operation_result.code} #{connection.get_operation_result.message}") if logger
|
||||
switch_server unless connection.get_operation_result.code == 49
|
||||
false
|
||||
end
|
||||
rescue Net::LDAP::LdapError => error
|
||||
logger.info("Error attempting to authenticate #{login.to_s} by #{server}: #{error.message}") if logger
|
||||
switch_server
|
||||
false
|
||||
end
|
||||
else
|
||||
connection.unbind if connection.bound?
|
||||
begin
|
||||
connection.bind(login_format % login.to_s, password.to_s)
|
||||
connection.unbind
|
||||
logger.info("Authenticated #{login.to_s} by #{server}") if logger
|
||||
true
|
||||
rescue LDAP::ResultError => error
|
||||
connection.unbind if connection.bound?
|
||||
logger.info("Error attempting to authenticate #{login.to_s} by #{server}: #{error.message}") if logger
|
||||
switch_server unless error.message == 'Invalid credentials'
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,4 +0,0 @@
|
|||
# desc "Explaining what the task does"
|
||||
# task :simple_ldap_authenticator do
|
||||
# # Task goes here
|
||||
# end
|
|
@ -1,8 +0,0 @@
|
|||
require 'test/unit'
|
||||
|
||||
class SimpleLdapAuthenticatorTest < Test::Unit::TestCase
|
||||
# Replace this with your real tests.
|
||||
def test_this_plugin
|
||||
flunk
|
||||
end
|
||||
end
|
2
vendor/plugins/skinny_spec/.gitignore
vendored
2
vendor/plugins/skinny_spec/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
|||
.DS_Store
|
||||
doc
|
270
vendor/plugins/skinny_spec/README.rdoc
vendored
270
vendor/plugins/skinny_spec/README.rdoc
vendored
|
@ -1,270 +0,0 @@
|
|||
= Skinny Spec
|
||||
|
||||
Skinny Spec is a collection of spec helper methods designed to help trim the fat and DRY up
|
||||
some of the bloat that sometimes results from properly specing your classes and templates.
|
||||
|
||||
== Requirements and Recommendations
|
||||
|
||||
Obviously you'll need to be using RSpec[http://github.com/dchelimsky/rspec/tree/master] and
|
||||
Rspec-Rails[http://github.com/dchelimsky/rspec-rails/tree/master] as your testing framework.
|
||||
|
||||
Skinny Spec was originally designed [and best enjoyed] if you're using
|
||||
Haml[http://github.com/nex3/haml/tree/master] and
|
||||
make_resourceful[http://github.com/rsl/make_resourceful/tree/master] but will default to
|
||||
ERb and a facsimile of Rails' default scaffolding [for the views and controllers, respectively]
|
||||
if Haml and/or make_resourceful are not available. I recommend using them though. :)
|
||||
|
||||
In addition, Skinny Spec uses Ruby2Ruby to make nicer expectation messages and you'll want to
|
||||
have that installed as well. It's not a dependency or anything but it <i>is</i> highly
|
||||
recommended.
|
||||
|
||||
== Setup
|
||||
|
||||
Once you've installed the plugin in your app's vendor/plugins folder, you're ready to rock!
|
||||
Skinny Spec includes itself into the proper RSpec classes so there's no configuration on your
|
||||
part. Sweet!
|
||||
|
||||
== Usage
|
||||
|
||||
The simplest way to use Skinny Specs is to generate a resource scaffold:
|
||||
|
||||
script/generate skinny_scaffold User
|
||||
|
||||
This command takes the usual complement of attribute definitions like
|
||||
<tt>script/generate scaffold</tt>. Then have a look at the generated files (particularly the
|
||||
specs) to see what's new and different with Skinny Spec.
|
||||
|
||||
=== Controller Specs
|
||||
|
||||
Let's look at the controller specs.
|
||||
|
||||
describe UsersController do
|
||||
describe "GET :index" do
|
||||
before(:each) do
|
||||
@users = stub_index(User)
|
||||
end
|
||||
|
||||
it_should_find_and_assign :users
|
||||
it_should_render :template, "index"
|
||||
end
|
||||
|
||||
# ...
|
||||
|
||||
describe "POST :create" do
|
||||
describe "when successful" do
|
||||
before(:each) do
|
||||
@user = stub_create(User)
|
||||
end
|
||||
|
||||
it_should_initialize_and_save :user
|
||||
it_should_redirect_to { user_url(@user) }
|
||||
end
|
||||
|
||||
# ...
|
||||
|
||||
First thing you should see is an example group for <tt>GET :index</tt>. That <tt>stub_index</tt> method there
|
||||
does a lot of work behind the curtain. I'll leave it up to you to check the documentation for it
|
||||
(and its brothers and sister methods like <tt>stub_new</tt>) but I will point out that the
|
||||
methods named <tt>stub_<i>controller_method</i></tt> should only be used for stubbing and
|
||||
mocking the main object of the method. To create mocks for other ancillary objects, please
|
||||
use <tt>stub_find_all</tt>, <tt>stub_find_one</tt>, and <tt>stub_initialize</tt>. The reason
|
||||
for this is because the former methods actually save us a step by defining an implicit
|
||||
controller method request. If you add a new method to your resource routing, you'll want to
|
||||
use the helper method <tt>define_request</tt> in those example groups to define an explicit
|
||||
request, like so:
|
||||
|
||||
describe "PUT :demote" do
|
||||
define_request { put :demote }
|
||||
|
||||
# ...
|
||||
end
|
||||
|
||||
You can also define a method called <tt>shared_request</tt> to "share" a
|
||||
<tt>define_request</tt> across nested describe blocks, like so:
|
||||
|
||||
describe "POST :create" do
|
||||
def shared_request
|
||||
post :create
|
||||
end
|
||||
|
||||
describe "when successful" do
|
||||
# ...
|
||||
end
|
||||
|
||||
describe "when unsuccessful" do
|
||||
# ...
|
||||
end
|
||||
end
|
||||
|
||||
Note: When you're adding longer, more complicated controller specs you can still leverage
|
||||
implicit and explicit requests by calling <tt>do_request</tt> in your spec as in the following
|
||||
example:
|
||||
|
||||
# Note this controller is UsersController and _not_ CategoriesController
|
||||
# and that loading the categories isn't part of the default actions
|
||||
# and cannot use the <tt>stub_<i>controller_method</i></tt> helpers
|
||||
# [which create implicit requests based on the controller method in the name]
|
||||
# but uses <tt>stub_find_all</tt> instead
|
||||
describe "GET :new" do
|
||||
before(:each) do
|
||||
@user = stub_new(User)
|
||||
@categories = stub_find_all(Category)
|
||||
end
|
||||
|
||||
# ...
|
||||
|
||||
it "should preload categories" do
|
||||
Category.should_receive(:find).with(:all)
|
||||
do_request
|
||||
end
|
||||
|
||||
it "should assign @categories" do
|
||||
do_request
|
||||
assigns[:categories].should == @categories
|
||||
end
|
||||
end
|
||||
|
||||
Finally we get to the meat of the spec and of Skinny Specs itself: the actual expectations.
|
||||
The first thing you'll notice is the use of example group (read: "describe" block) level methods
|
||||
instead of the usual example (read: "it") blocks. Using this helper at the example group level
|
||||
saves us three lines over using an example block. (If this isn't significant to you, this is
|
||||
probably the wrong plugin for you as well. Sorry.) Note that none of these methods use the
|
||||
instance variables defined in the "before" block because they are all nil at the example block
|
||||
level. Let's look at a sample method to see how it works:
|
||||
|
||||
it_should_find_and_assign :users
|
||||
|
||||
This actually wraps two different expectations: one that <tt>User.should_receive(:find).with(:all)</tt>
|
||||
and another that the instance variable <tt>@users</tt> is assigned with the return value from that finder call.
|
||||
If you need to add more detailed arguments to the find, you can easily break this into two different
|
||||
expectations like:
|
||||
|
||||
it_should_find :users, :limit => 2
|
||||
it_should_assign :users
|
||||
|
||||
See the documentation for the <tt>it_should_find</tt> for more information. You might have guessed that
|
||||
<tt>it_should_initialize_assign</tt> and <tt>it_should_render_template</tt> work in a similar
|
||||
fashion and you'd be right. Again, see the documentation for these individual methods for more
|
||||
information. Lots of information in those docs.
|
||||
|
||||
A useful helper method that doesn't appear in any of the scaffolding is <tt>with_default_restful_actions</tt>
|
||||
which takes a block and evaluates it for each of the RESTful controller actions. Very useful for
|
||||
spec'ing that these methods redirect to the login page when the user isn't logged in, for example. This
|
||||
method is designed to be used inside an example like so:
|
||||
|
||||
describe "when not logged in" do
|
||||
it "should redirect all requests to the login page" do
|
||||
with_default_restful_actions do
|
||||
response.should redirect_to(login_url)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Before we're through with the controller specs, let me point out one more important detail. In
|
||||
order to use <tt>it_should_redirect_to</tt> we have to send the routing inside a block argument
|
||||
there so it can be evaluated in the example context instead of the example group, where it
|
||||
completely blows up. This methodology is used anywhere routing is referred to in a "skinny",
|
||||
example group level spec.
|
||||
|
||||
=== View Specs
|
||||
|
||||
Now let's move to the view specs!
|
||||
|
||||
describe "/users/form.html.haml" do
|
||||
before(:each) do
|
||||
@user = mock_and_assign(User, :stub => {
|
||||
:name => "foo",
|
||||
:birthday => 1.week.ago,
|
||||
:adult => false
|
||||
})
|
||||
end
|
||||
|
||||
it_should_have_form_for :user
|
||||
|
||||
it_should_allow_editing :user, :name
|
||||
it_should_allow_editing :user, :birthday
|
||||
it_should_allow_editing :user, :adult
|
||||
|
||||
it_should_link_to_show :user
|
||||
it_should_link_to { users_path }
|
||||
end
|
||||
|
||||
Like the special <tt>stub_index</tt> methods in the controller
|
||||
specs, the view specs have a shorthand mock and stub helpers: <tt>mock_and_assign</tt> and
|
||||
<tt>mock_and_assign_collection</tt>. These are well documented so please check them out.
|
||||
|
||||
There are also some really nice helper methods that I'd like point out. First is
|
||||
<tt>it_should_have_form_for</tt>. This is a really good convenience wrapper that basically wraps
|
||||
the much longer:
|
||||
|
||||
it "should use form_for to generate the proper form action and options" do
|
||||
template.should_receive(:form_for).with(@user)
|
||||
do_render
|
||||
end
|
||||
|
||||
Next up is the <tt>it_should_allow_editing</tt> helper. I love this method the most because it
|
||||
really helps DRY up that view spec while at the same time being amazingly unbrittle. Instead of
|
||||
creating an expectation for a specific form element, this method creates a generalized expectation
|
||||
that there's a form element with the <tt>name</tt> attribute set in such away that it will
|
||||
generate the proper <tt>params</tt> to use in the controller to edit or create the instance.
|
||||
Check out the docs and the source for more information on this. Also check out
|
||||
<tt>it_should_have_form_element_for</tt> which is roughly equivalent for those times when you use
|
||||
<tt>form_tag</tt> instead.
|
||||
|
||||
Finally let's look at those <tt>it_should_link_to_<i>controller_method</i></tt> helpers.
|
||||
These methods (and there's one each for the controller methods
|
||||
<tt>new</tt>, <tt>edit</tt>, <tt>show</tt>, and <tt>delete</tt>) point to instance variables
|
||||
which you should be created in the "before" blocks with <tt>mock_and_assign</tt>. The other is
|
||||
<tt>it_should_allow_editing</tt> which is likewise covered extensively in the documentation and
|
||||
I will just point out here that, like <tt>it_should_link_to_edit</tt> and such, it takes a
|
||||
symbol for the name of the instance variable it refers to and <i>additionally</i> takes
|
||||
a symbol for the name of the attribute to be edited.
|
||||
|
||||
Also note that, when constructing a long form example, instead of defining an instance variable
|
||||
for the name of the template and calling <tt>render @that_template</tt> you can simply call
|
||||
<tt>do_render</tt> which takes the name of the template from the outermost example group where
|
||||
it is customarily stated.
|
||||
|
||||
=== Model Specs
|
||||
|
||||
Skinny Spec adds a matcher for the various ActiveRecord associations. On the example group level
|
||||
you call them like:
|
||||
|
||||
it_should_belong_to :manager
|
||||
it_should_have_many :clients
|
||||
|
||||
Within an example you can call them on either the class or the instance setup in the
|
||||
"before" block. These are equivalent:
|
||||
|
||||
@user.should belong_to(:group)
|
||||
User.should belong_to(:group)
|
||||
|
||||
I've also added some very basic validation helpers like <tt>it_should_validate_presence_of</tt>,
|
||||
<tt>it_should_validate_uniqueness_of</tt>, <tt>it_should_not_mass_assign</tt>. Please consult
|
||||
the documentation for more information.
|
||||
|
||||
== Miscellaneous Notes
|
||||
|
||||
In the scaffolding, I have used my own idiomatic Rails usage:
|
||||
|
||||
* All controller actions which use HTML forms [<tt>new</tt>, <tt>edit</tt>, etc] use a shared
|
||||
form and leverage <tt>form_for</tt> to its fullest by letting it create the appropriate
|
||||
action and options.
|
||||
* Some instances where you might expect link_to are button_to. This is to provide a common
|
||||
interface element which can be styled the same instead of a mishmash of links and buttons and
|
||||
inputs everywhere. To take full advantage of this, I usually override many of Rails' default
|
||||
helpers with custom ones that all use actual HTML <tt>BUTTON</tt> elements which are much
|
||||
easier to style than "button" typed <tt>INPUT</tt>. I've provided a text file in the
|
||||
"additional" folder of this plugin which you can use in your ApplicationHelper. (I also
|
||||
provide an optional override helper for the <tt>label</tt> method which uses
|
||||
<tt>#titleize</tt> instead of <tt>humanize</tt> for stylistic reasons).
|
||||
* Probably more that I can't think of.
|
||||
|
||||
== Credits and Thanks
|
||||
|
||||
Sections of this code were taken from or inspired by Rick Olsen's
|
||||
rspec_on_rails_on_crack[http://github.com/technoweenie/rspec_on_rails_on_crack/tree/master].
|
||||
Also thanks and props to Hampton Catlin and Nathan Weizenbaum for the lovely and imminently useable
|
||||
Haml and make_resourceful. Also also praises and glory to David Chelimsky and the Rspec crew.
|
||||
|
||||
Also thanks to Don Petersen, Nicolas Mérouze, Mikkel Malmberg, and Brandan Lennox for their suggestions and fixes.
|
11
vendor/plugins/skinny_spec/Rakefile
vendored
11
vendor/plugins/skinny_spec/Rakefile
vendored
|
@ -1,11 +0,0 @@
|
|||
require 'rake'
|
||||
require 'rake/rdoctask'
|
||||
|
||||
desc 'Generate documentation for the Skinny Spec plugin'
|
||||
Rake::RDocTask.new(:rdoc) do |rdoc|
|
||||
rdoc.rdoc_dir = 'doc'
|
||||
rdoc.title = 'Skinny Spec'
|
||||
rdoc.options << '--line-numbers' << '--inline-source'
|
||||
rdoc.rdoc_files.include('README.rdoc')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
end
|
|
@ -1,58 +0,0 @@
|
|||
# Please insert these into your ApplicationHelper
|
||||
|
||||
# Replacement for Rails' default submit_tag helper
|
||||
# using HTML button element rather than HTML input element
|
||||
def submit_tag(text, options = {})
|
||||
content_tag :button, text, options.merge(:type => :submit)
|
||||
end
|
||||
|
||||
# Replacement for Rails' default button_to helper
|
||||
# using HTML button element rather than HTML input element
|
||||
def button_to(name, options = {}, html_options = {})
|
||||
html_options = html_options.stringify_keys
|
||||
convert_boolean_attributes!(html_options, %w( disabled ))
|
||||
|
||||
method_tag = ''
|
||||
if (method = html_options.delete('method')) && %w{put delete}.include?(method.to_s)
|
||||
method_tag = tag('input', :type => 'hidden', :name => '_method', :value => method.to_s)
|
||||
end
|
||||
|
||||
form_method = method.to_s == 'get' ? 'get' : 'post'
|
||||
|
||||
request_token_tag = ''
|
||||
if form_method == 'post' && protect_against_forgery?
|
||||
request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token)
|
||||
end
|
||||
|
||||
if confirm = html_options.delete("confirm")
|
||||
html_options["onclick"] = "return #{confirm_javascript_function(confirm)};"
|
||||
end
|
||||
|
||||
url = options.is_a?(String) ? options : self.url_for(options)
|
||||
name ||= url
|
||||
|
||||
html_options.merge!("type" => "submit", "value" => name)
|
||||
|
||||
"<form method=\"#{form_method}\" action=\"#{escape_once url}\" class=\"button-to\"><div>" +
|
||||
method_tag + content_tag("button", name, html_options) + request_token_tag + "</div></form>"
|
||||
end
|
||||
|
||||
# Replacement for Rails' default button_to_function helper
|
||||
# using HTML button element rather than HTML input element
|
||||
def button_to_function(name, *args, &block)
|
||||
html_options = args.extract_options!
|
||||
function = args[0] || ''
|
||||
|
||||
html_options.symbolize_keys!
|
||||
function = update_page(&block) if block_given?
|
||||
content_tag(:button, name, html_options.merge({
|
||||
:onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
|
||||
}))
|
||||
end
|
||||
|
||||
# Replacement for Rails' default label helper
|
||||
# using String#titleize rather than String#humanize
|
||||
def label(object_name, method, text = nil, options = {})
|
||||
text ||= method.to_s[].titleize
|
||||
super
|
||||
end
|
|
@ -1,102 +0,0 @@
|
|||
class SkinnyScaffoldGenerator < Rails::Generator::NamedBase
|
||||
attr_reader :controller_class_path, :controller_file_path, :controller_class_nesting,
|
||||
:controller_class_nesting_depth, :controller_class_name, :controller_underscore_name,
|
||||
:controller_plural_name, :template_language
|
||||
alias_method :controller_file_name, :controller_underscore_name
|
||||
alias_method :controller_singular_name, :controller_file_name
|
||||
alias_method :controller_table_name, :controller_plural_name
|
||||
|
||||
default_options :skip_migration => false
|
||||
|
||||
def initialize(runtime_args, runtime_options = {})
|
||||
super
|
||||
|
||||
base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@name.pluralize)
|
||||
@controller_class_name_without_nesting, @controller_underscore_name, @controller_plural_name = inflect_names(base_name)
|
||||
|
||||
if @controller_class_nesting.empty?
|
||||
@controller_class_name = @controller_class_name_without_nesting
|
||||
else
|
||||
@controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}"
|
||||
end
|
||||
end
|
||||
|
||||
def manifest
|
||||
record do |m|
|
||||
# Check for class naming collisions
|
||||
m.class_collisions controller_class_path, "#{controller_class_name}Controller", "#{controller_class_name}Helper"
|
||||
m.class_collisions class_path, "#{class_name}"
|
||||
|
||||
# # Controller, helper, and views directories
|
||||
m.directory File.join('app', 'views', controller_class_path, controller_file_name)
|
||||
m.directory File.join('spec', 'views', controller_class_path, controller_file_name)
|
||||
m.directory File.join('app', 'helpers', controller_class_path)
|
||||
m.directory File.join('spec', 'helpers', controller_class_path)
|
||||
m.directory File.join('app', 'controllers', controller_class_path)
|
||||
m.directory File.join('spec', 'controllers', controller_class_path)
|
||||
m.directory File.join('app', 'models', class_path)
|
||||
m.directory File.join('spec', 'models', class_path)
|
||||
|
||||
# Views
|
||||
@template_language = defined?(Haml) ? "haml" : "erb"
|
||||
%w{index show form}.each do |action|
|
||||
m.template "#{action}.html.#{template_language}",
|
||||
File.join('app/views', controller_class_path, controller_file_name, "#{action}.html.#{template_language}")
|
||||
m.template "#{action}.html_spec.rb",
|
||||
File.join('spec/views', controller_class_path, controller_file_name, "#{action}.html.#{template_language}_spec.rb")
|
||||
end
|
||||
m.template "index_partial.html.#{template_language}",
|
||||
File.join('app/views', controller_class_path, controller_file_name, "_#{file_name}.html.#{template_language}")
|
||||
m.template 'index_partial.html_spec.rb',
|
||||
File.join('spec/views', controller_class_path, controller_file_name, "_#{file_name}.html.#{template_language}_spec.rb")
|
||||
|
||||
# Helper
|
||||
m.template 'helper.rb',
|
||||
File.join('app/helpers', controller_class_path, "#{controller_file_name}_helper.rb")
|
||||
m.template 'helper_spec.rb',
|
||||
File.join('spec/helpers', controller_class_path, "#{controller_file_name}_helper_spec.rb")
|
||||
|
||||
# Controller
|
||||
m.template 'controller.rb',
|
||||
File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb")
|
||||
m.template 'controller_spec.rb',
|
||||
File.join('spec/controllers', controller_class_path, "#{controller_file_name}_controller_spec.rb")
|
||||
|
||||
# Model
|
||||
m.template 'model.rb',
|
||||
File.join('app/models', class_path, "#{file_name}.rb")
|
||||
m.template 'model_spec.rb',
|
||||
File.join('spec/models', class_path, "#{file_name}_spec.rb")
|
||||
|
||||
# Routing
|
||||
m.route_resources controller_file_name
|
||||
|
||||
unless options[:skip_migration]
|
||||
m.migration_template(
|
||||
'migration.rb', 'db/migrate',
|
||||
:assigns => {
|
||||
:migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}",
|
||||
:attributes => attributes
|
||||
},
|
||||
:migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
def banner
|
||||
"Usage: #{$0} skinny_scaffold ModelName [field:type, field:type]"
|
||||
end
|
||||
|
||||
def add_options!(opt)
|
||||
opt.separator ''
|
||||
opt.separator 'Options:'
|
||||
opt.on("--skip-migration",
|
||||
"Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
|
||||
end
|
||||
|
||||
def model_name
|
||||
class_name.demodulize
|
||||
end
|
||||
end
|
|
@ -1,105 +0,0 @@
|
|||
class <%= controller_class_name %>Controller < ApplicationController
|
||||
<%- if defined?(Resourceful::Maker) -%>
|
||||
make_resourceful do
|
||||
actions :all
|
||||
|
||||
# Let's get the most use from form_for and share a single form here!
|
||||
response_for :new, :edit do
|
||||
render :template => "<%= plural_name %>/form"
|
||||
end
|
||||
|
||||
response_for :create_fails, :update_fails do
|
||||
flash[:error] = "There was a problem!"
|
||||
render :template => "<%= plural_name %>/form"
|
||||
end
|
||||
end
|
||||
<%- else -%>
|
||||
# GET /<%= table_name %>
|
||||
# GET /<%= table_name %>.xml
|
||||
def index
|
||||
@<%= table_name %> = <%= class_name %>.find(:all)
|
||||
|
||||
respond_to do |format|
|
||||
format.html # index.html.erb
|
||||
format.xml { render :xml => @<%= table_name %> }
|
||||
end
|
||||
end
|
||||
|
||||
# GET /<%= table_name %>/1
|
||||
# GET /<%= table_name %>/1.xml
|
||||
def show
|
||||
@<%= file_name %> = <%= class_name %>.find(params[:id])
|
||||
|
||||
respond_to do |format|
|
||||
format.html # show.html.erb
|
||||
format.xml { render :xml => @<%= file_name %> }
|
||||
end
|
||||
end
|
||||
|
||||
# GET /<%= table_name %>/new
|
||||
# GET /<%= table_name %>/new.xml
|
||||
def new
|
||||
@<%= file_name %> = <%= class_name %>.new
|
||||
|
||||
respond_to do |format|
|
||||
format.html { render :template => "<%= plural_name %>/form" }
|
||||
format.xml { render :xml => @<%= file_name %> }
|
||||
end
|
||||
end
|
||||
|
||||
# GET /<%= table_name %>/1/edit
|
||||
def edit
|
||||
@<%= file_name %> = <%= class_name %>.find(params[:id])
|
||||
render :template => "<%= plural_name %>/form"
|
||||
end
|
||||
|
||||
# POST /<%= table_name %>
|
||||
# POST /<%= table_name %>.xml
|
||||
def create
|
||||
@<%= file_name %> = <%= class_name %>.new(params[:<%= file_name %>])
|
||||
|
||||
respond_to do |format|
|
||||
if @<%= file_name %>.save
|
||||
flash[:notice] = '<%= class_name %> was successfully created.'
|
||||
format.html { redirect_to(@<%= file_name %>) }
|
||||
format.xml { render :xml => @<%= file_name %>, :status => :created, :location => @<%= file_name %> }
|
||||
else
|
||||
flash.now[:error] = '<%= class_name %> could not be created.'
|
||||
format.html { render :template => "<%= plural_name %>/form" }
|
||||
format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# PUT /<%= table_name %>/1
|
||||
# PUT /<%= table_name %>/1.xml
|
||||
def update
|
||||
@<%= file_name %> = <%= class_name %>.find(params[:id])
|
||||
|
||||
respond_to do |format|
|
||||
if @<%= file_name %>.update_attributes(params[:<%= file_name %>])
|
||||
flash[:notice] = '<%= class_name %> was successfully updated.'
|
||||
format.html { redirect_to(@<%= file_name %>) }
|
||||
format.xml { head :ok }
|
||||
else
|
||||
flash.now[:error] = '<%= class_name %> could not be created.'
|
||||
format.html { render :template => "<%= plural_name %>/form" }
|
||||
format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /<%= table_name %>/1
|
||||
# DELETE /<%= table_name %>/1.xml
|
||||
def destroy
|
||||
@<%= file_name %> = <%= class_name %>.find(params[:id])
|
||||
@<%= file_name %>.destroy
|
||||
|
||||
respond_to do |format|
|
||||
flash[:notice] = '<%= class_name %> was successfully deleted.'
|
||||
format.html { redirect_to(<%= table_name %>_url) }
|
||||
format.xml { head :ok }
|
||||
end
|
||||
end
|
||||
<%- end -%>
|
||||
end
|
|
@ -1,93 +0,0 @@
|
|||
require File.dirname(__FILE__) + '/../spec_helper'
|
||||
|
||||
describe <%= controller_class_name %>Controller do
|
||||
describe "GET :index" do
|
||||
before(:each) do
|
||||
@<%= plural_name %> = stub_index(<%= class_name %>)
|
||||
end
|
||||
|
||||
it_should_find_and_assign :<%= plural_name %>
|
||||
it_should_render_template "index"
|
||||
end
|
||||
|
||||
describe "GET :new" do
|
||||
before(:each) do
|
||||
@<%= singular_name %> = stub_new(<%= class_name %>)
|
||||
end
|
||||
|
||||
it_should_initialize_and_assign :<%= singular_name %>
|
||||
it_should_render_template "form"
|
||||
end
|
||||
|
||||
describe "POST :create" do
|
||||
describe "when successful" do
|
||||
before(:each) do
|
||||
@<%= singular_name %> = stub_create(<%= class_name %>)
|
||||
end
|
||||
|
||||
it_should_initialize_and_save :<%= singular_name %>
|
||||
it_should_set_flash :notice
|
||||
it_should_redirect_to { <%= singular_name %>_url(@<%= singular_name %>) }
|
||||
end
|
||||
|
||||
describe "when unsuccessful" do
|
||||
before(:each) do
|
||||
@<%= singular_name %> = stub_create(<%= class_name %>, :return => :false)
|
||||
end
|
||||
|
||||
it_should_initialize_and_assign :<%= singular_name %>
|
||||
it_should_set_flash :error
|
||||
it_should_render_template "form"
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET :show" do
|
||||
before(:each) do
|
||||
@<%= singular_name %> = stub_show(<%= class_name %>)
|
||||
end
|
||||
|
||||
it_should_find_and_assign :<%= singular_name %>
|
||||
it_should_render_template "show"
|
||||
end
|
||||
|
||||
describe "GET :edit" do
|
||||
before(:each) do
|
||||
@<%= singular_name %> = stub_edit(<%= class_name %>)
|
||||
end
|
||||
|
||||
it_should_find_and_assign :<%= singular_name %>
|
||||
it_should_render_template "form"
|
||||
end
|
||||
|
||||
describe "PUT :update" do
|
||||
describe "when successful" do
|
||||
before(:each) do
|
||||
@<%= singular_name %> = stub_update(<%= class_name %>)
|
||||
end
|
||||
|
||||
it_should_find_and_update :<%= singular_name %>
|
||||
it_should_set_flash :notice
|
||||
it_should_redirect_to { <%= singular_name %>_url(@<%= singular_name %>) }
|
||||
end
|
||||
|
||||
describe "when unsuccessful" do
|
||||
before(:each) do
|
||||
@<%= singular_name %> = stub_update(<%= class_name %>, :return => :false)
|
||||
end
|
||||
|
||||
it_should_find_and_assign :<%= singular_name %>
|
||||
it_should_set_flash :error
|
||||
it_should_render_template "form"
|
||||
end
|
||||
end
|
||||
|
||||
describe "DELETE :destroy" do
|
||||
before(:each) do
|
||||
@<%= singular_name %> = stub_destroy(<%= class_name %>)
|
||||
end
|
||||
|
||||
it_should_find_and_destroy :<%= singular_name %>
|
||||
it_should_set_flash :notice
|
||||
it_should_redirect_to { <%= plural_name %>_url }
|
||||
end
|
||||
end
|
|
@ -1,25 +0,0 @@
|
|||
<h1><%= singular_name %>.new_record? ? "New" : "Edit" %> <%= model_name %></h1>
|
||||
<%% form_for(@<%= singular_name %>) do |f| %>
|
||||
<div id="form_errors">
|
||||
<%%= f.error_messages %>
|
||||
</div>
|
||||
<%- if attributes.blank? -%>
|
||||
<p>Add your form elements here, please!</p>
|
||||
<%- else -%>
|
||||
<%- attributes.each do |attribute| -%>
|
||||
<p>
|
||||
<%%= f.label :<%= attribute.name %> %><br />
|
||||
<%%= f.<%= attribute.field_type %> :<%= attribute.name %> %>
|
||||
</p>
|
||||
<%- end -%>
|
||||
<%- end -%>
|
||||
<div id="commands">
|
||||
<%%= submit_tag "Save" %>
|
||||
<div id="navigation_commands">
|
||||
<%% unless @<%= singular_name %>.new_record? -%>
|
||||
<%%= button_to "Show", <%= singular_name %>_path(@<%= singular_name %>), :method => "get", :title => "Show <%= singular_name %>. Unsaved changes will be lost." %>
|
||||
<%% end -%>
|
||||
<%%= button_to "Back to List", <%= plural_name %>_path, :class => "cancel", :method => "get", :title => "Return to <%= singular_name %> list without saving changes" %>
|
||||
</div>
|
||||
</div>
|
||||
<%% end -%>
|
|
@ -1,18 +0,0 @@
|
|||
%h1== #{@<%= singular_name %>.new_record? ? "New" : "Edit"} #{<%= model_name %>}
|
||||
- form_for @<%= singular_name %> do |f|
|
||||
#form_errors= f.error_messages
|
||||
<% if attributes.blank? -%>
|
||||
%p Add your form elements here, please!
|
||||
<% else -%>
|
||||
<%- attributes.each do |attribute| -%>
|
||||
%p
|
||||
= f.label :<%= attribute.name %>
|
||||
= f.<%= attribute.field_type %> :<%= attribute.name %>
|
||||
<%- end -%>
|
||||
<% end -%>
|
||||
#commands
|
||||
= submit_tag "Save"
|
||||
#navigation_commands
|
||||
- unless @<%= singular_name %>.new_record?
|
||||
= button_to "Show", <%= singular_name %>_path(@<%= singular_name %>), :method => "get", :title => "Show <%= singular_name %>. Unsaved changes will be lost."
|
||||
= button_to "Back to List", <%= plural_name %>_path, :class => "cancel", :method => "get", :title => "Return to <%= singular_name %> list without saving changes"
|
|
@ -1,40 +0,0 @@
|
|||
require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../../spec_helper'
|
||||
|
||||
describe "<%= File.join(controller_class_path, controller_singular_name) %>/form.html.<%= template_language %>" do
|
||||
before(:each) do
|
||||
@<%= singular_name %> = mock_and_assign(<%= model_name %>, :stub => {
|
||||
<% if attributes.blank? -%>
|
||||
# Add your stub attributes and return values here like:
|
||||
# :name => "Foo", :address => "815 Oceanic Drive"
|
||||
<% else -%>
|
||||
<%- attributes.each_with_index do |attribute, index| -%>
|
||||
<%- case attribute.type when :string, :text -%>
|
||||
:<%= attribute.name %> => "foo"<%= index < attributes.size - 1 ? "," : "" %>
|
||||
<%- when :integer, :float, :decimal -%>
|
||||
:<%= attribute.name %> => 815<%= index < attributes.size - 1 ? "," : "" %>
|
||||
<%- when :boolean -%>
|
||||
:<%= attribute.name %> => false<%= index < attributes.size - 1 ? "," : "" %>
|
||||
<%- when :date, :datetime, :time, :timestamp -%>
|
||||
:<%= attribute.name %> => 1.week.ago<%= index < attributes.size - 1 ? "," : "" %>
|
||||
<%- else -%>
|
||||
:<%= attribute.name %> => nil<%= index < attributes.size - 1 ? "," : "" %> # Could not determine valid attribute
|
||||
<%- end -%>
|
||||
<%- end -%>
|
||||
<% end -%>
|
||||
})
|
||||
end
|
||||
|
||||
it_should_have_form_for :<%= singular_name %>
|
||||
<% if attributes.blank? -%>
|
||||
# Add specs for editing attributes here, please! Like this:
|
||||
#
|
||||
# it_should_allow_editing :<%= singular_name %>, :foo
|
||||
<% else -%>
|
||||
<%- attributes.each do |attribute| -%>
|
||||
it_should_allow_editing :<%= singular_name %>, :<%= attribute.name %>
|
||||
<%- end -%>
|
||||
<% end -%>
|
||||
|
||||
it_should_link_to_show :<%= singular_name %>
|
||||
it_should_link_to { <%= plural_name %>_path }
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
module <%= controller_class_name %>Helper
|
||||
end
|
|
@ -1,5 +0,0 @@
|
|||
require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../spec_helper'
|
||||
|
||||
describe <%= controller_class_name %>Helper do
|
||||
# Add your specs here or remove this file completely, please!
|
||||
end
|
|
@ -1,31 +0,0 @@
|
|||
<h1><%= model_name %> List</h1>
|
||||
<table>
|
||||
<%%- if @<%= plural_name %>.empty? -%>
|
||||
<tbody>
|
||||
<tr class="empty">
|
||||
<td>There are no <%= plural_name.humanize.downcase %></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<%%- else -%>
|
||||
<thead>
|
||||
<tr>
|
||||
<%- if attributes.blank? -%>
|
||||
<th><!-- Generic display column --></th>
|
||||
<%- else -%>
|
||||
<%- attributes.each do |attribute| -%>
|
||||
<th><%= attribute.name.titleize %></th>
|
||||
<%- end -%>
|
||||
<%- end -%>
|
||||
<th class="show"><!-- "Show" link column --></th>
|
||||
<th class="edit"><!-- "Edit" link column --></th>
|
||||
<th class="delete"><!-- "Delete" link column --></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%%= render :partial => @<%= plural_name %> %>
|
||||
</tbody>
|
||||
<%%- end -%>
|
||||
</table>
|
||||
<div id="commands">
|
||||
<%%= button_to "New <%= singular_name.titleize %>", new_<%= singular_name %>_path, :method => "get" %>
|
||||
</div>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue