mirror of
https://github.com/TracksApp/tracks.git
synced 2025-12-28 21:08:48 +01:00
Merge branch 'master' of git://github.com/bsag/tracks into bsag
This commit is contained in:
commit
b331985e62
25 changed files with 233 additions and 109 deletions
|
|
@ -163,6 +163,7 @@ class ProjectsController < ApplicationController
|
|||
end
|
||||
|
||||
def destroy
|
||||
@project.recurring_todos.each {|rt| rt.remove_from_project!}
|
||||
@project.destroy
|
||||
@active_projects_count = current_user.projects.active.count
|
||||
@hidden_projects_count = current_user.projects.hidden.count
|
||||
|
|
|
|||
|
|
@ -71,9 +71,17 @@ class UsersController < ApplicationController
|
|||
render :action => "nosignup", :layout => "login"
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
user = User.new(params['user'])
|
||||
|
||||
if Tracks::Config.auth_schemes.include?('ldap') &&
|
||||
user.auth_type == 'ldap' &&
|
||||
!SimpleLdapAuthenticator.valid?(user.login, params['user']['password'])
|
||||
notify :warning, "Incorrect password"
|
||||
redirect_to :action => 'new'
|
||||
return
|
||||
end
|
||||
|
||||
if Tracks::Config.auth_schemes.include?('cas')
|
||||
if user.auth_type.eql? "cas"
|
||||
user.crypted_password = "cas"
|
||||
|
|
|
|||
|
|
@ -196,17 +196,21 @@ module ApplicationHelper
|
|||
# do not change string; URL is alreay linked
|
||||
href
|
||||
else
|
||||
content_tag(:a, h(href), :href => h(href))
|
||||
content = content_tag(:a, h(href), :href => h(href))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def format_note(note)
|
||||
note.gsub!(/</, '<') # eliminate tags
|
||||
note.gsub!(/>/, '>')
|
||||
note = markdown(note)
|
||||
note = auto_link_message(note)
|
||||
note = auto_link(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
|
||||
end
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ module TodosHelper
|
|||
:title => 'Drag onto another action to make it depend on that action',
|
||||
:class => 'grip') +
|
||||
image_tag('blank.png', :width => 16, :height => 16, :border => 0,
|
||||
:title => "Drop an action to make it depend on this action", :class => 'successor_target')
|
||||
:title => "Drop an action to make it depend on this action", :class => 'successor_target drop_target')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
class Context < ActiveRecord::Base
|
||||
|
||||
has_many :todos, :dependent => :delete_all, :include => :project, :order => "todos.completed_at DESC"
|
||||
has_many :recurring_todos, :dependent => :delete_all
|
||||
belongs_to :user
|
||||
|
||||
named_scope :active, :conditions => { :hide => false }
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ class Project < ActiveRecord::Base
|
|||
:order => "show_from"
|
||||
|
||||
has_many :notes, :dependent => :delete_all, :order => "created_at DESC"
|
||||
has_many :recurring_todos
|
||||
|
||||
belongs_to :default_context, :class_name => "Context", :foreign_key => "default_context_id"
|
||||
belongs_to :user
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ class RecurringTodo < ActiveRecord::Base
|
|||
|
||||
has_many :todos
|
||||
|
||||
named_scope :active, :conditions => { :state => 'active'}
|
||||
named_scope :completed, :conditions => { :state => 'completed'}
|
||||
|
||||
attr_protected :user
|
||||
|
||||
acts_as_state_machine :initial => :active, :column => 'state'
|
||||
|
|
@ -15,22 +18,91 @@ class RecurringTodo < ActiveRecord::Base
|
|||
t.occurences_count = 0
|
||||
}
|
||||
state :completed, :enter => Proc.new { |t| t.completed_at = Time.zone.now }, :exit => Proc.new { |t| t.completed_at = nil }
|
||||
|
||||
event :complete do
|
||||
transitions :to => :completed, :from => [:active]
|
||||
end
|
||||
|
||||
event :activate do
|
||||
transitions :to => :active, :from => [:completed]
|
||||
end
|
||||
|
||||
validates_presence_of :description
|
||||
validates_presence_of :recurring_period
|
||||
validates_length_of :description, :maximum => 100
|
||||
validates_length_of :notes, :maximum => 60000, :allow_nil => true
|
||||
|
||||
validates_presence_of :context
|
||||
|
||||
named_scope :active, :conditions => { :state => 'active'}
|
||||
named_scope :completed, :conditions => { :state => 'completed'}
|
||||
|
||||
event :complete do
|
||||
transitions :to => :completed, :from => [:active]
|
||||
end
|
||||
validate :period_specific_validations
|
||||
validate :starts_and_ends_on_validations
|
||||
|
||||
event :activate do
|
||||
transitions :to => :active, :from => [:completed]
|
||||
def period_specific_validations
|
||||
periods = %W[daily weekly monthly yearly]
|
||||
if periods.include?(recurring_period)
|
||||
self.send("validate_#{recurring_period}")
|
||||
else
|
||||
errors.add(:recurring_period, "is an unknown recurrence pattern: '#{self.recurring_period}'")
|
||||
end
|
||||
end
|
||||
|
||||
def validate_daily
|
||||
if (!only_work_days) && (daily_every_x_days.nil? || daily_every_x_days.blank?)
|
||||
errors.add_to_base("Every other nth day may not be empty for recurrence setting")
|
||||
end
|
||||
end
|
||||
|
||||
def validate_weekly
|
||||
if weekly_every_x_week.nil? || weekly_every_x_week.blank?
|
||||
errors.add_to_base("Every other nth week may not be empty for recurrence setting")
|
||||
end
|
||||
something_set = false
|
||||
%w{sunday monday tuesday wednesday thursday friday}.each do |day|
|
||||
something_set ||= self.send("on_#{day}")
|
||||
|
||||
end
|
||||
errors.add_to_base("You must specify at least one day on which the todo recurs") if !something_set
|
||||
end
|
||||
|
||||
def validate_monthly
|
||||
case recurrence_selector
|
||||
when 0 # 'monthly_every_x_day'
|
||||
errors.add_to_base("The day of the month may not be empty for recurrence setting") if monthly_every_x_day.nil? || monthly_every_x_day.blank?
|
||||
errors.add_to_base("Every other nth month may not be empty for recurrence setting") if monthly_every_x_month.nil? || monthly_every_x_month.blank?
|
||||
when 1 # 'monthly_every_xth_day'
|
||||
errors.add_to_base("Every other nth month may not be empty for recurrence setting") if monthly_every_x_month2.nil? || monthly_every_x_month2.blank?
|
||||
errors.add_to_base("The nth day of the month may not be empty for recurrence setting") if monthly_every_xth_day.nil? || monthly_every_xth_day.blank?
|
||||
errors.add_to_base("The day of the month may not be empty for recurrence setting") if monthly_day_of_week.nil? || monthly_day_of_week.blank?
|
||||
else
|
||||
raise Exception.new, "unexpected value of recurrence selector '#{self.recurrence_selector}'"
|
||||
end
|
||||
end
|
||||
|
||||
def validate_yearly
|
||||
case recurrence_selector
|
||||
when 0 # 'yearly_every_x_day'
|
||||
errors.add_to_base("The month of the year may not be empty for recurrence setting") if yearly_month_of_year.nil? || yearly_month_of_year.blank?
|
||||
errors.add_to_base("The day of the month may not be empty for recurrence setting") if yearly_every_x_day.nil? || yearly_every_x_day.blank?
|
||||
when 1 # 'yearly_every_xth_day'
|
||||
errors.add_to_base("The month of the year may not be empty for recurrence setting") if yearly_month_of_year2.nil? || yearly_month_of_year2.blank?
|
||||
errors.add_to_base("The nth day of the month may not be empty for recurrence setting") if yearly_every_xth_day.nil? || yearly_every_xth_day.blank?
|
||||
errors.add_to_base("The day of the week may not be empty for recurrence setting") if yearly_day_of_week.nil? || yearly_day_of_week.blank?
|
||||
else
|
||||
raise Exception.new, "unexpected value of recurrence selector '#{self.recurrence_selector}'"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def starts_and_ends_on_validations
|
||||
errors.add_to_base("The start date needs to be filled in") if start_from.nil? || start_from.blank?
|
||||
case self.ends_on
|
||||
when 'ends_on_number_of_times'
|
||||
errors.add_to_base("The number of recurrences needs to be filled in for 'Ends on'") if number_of_occurences.nil? || number_of_occurences.blank?
|
||||
when "ends_on_end_date"
|
||||
errors.add_to_base("The end date needs to be filled in for 'Ends on'") if end_date.nil? || end_date.blank?
|
||||
else
|
||||
errors.add_to_base("The end of the recurrence is not selected") unless ends_on == "no_end_date"
|
||||
end
|
||||
end
|
||||
|
||||
# the following recurrence patterns can be stored:
|
||||
|
|
@ -64,7 +136,7 @@ class RecurringTodo < ActiveRecord::Base
|
|||
when 'daily_every_work_day'
|
||||
self.only_work_days = true
|
||||
else
|
||||
raise Exception.new, "unknown daily recurrence pattern: '#{selector}'"
|
||||
raise Exception.new, "unknown daily recurrence pattern: '#{selector}'"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -199,7 +271,7 @@ class RecurringTodo < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def monthly_every_x_month2=(x)
|
||||
def monthly_every_x_month2=(x)
|
||||
self.every_other2 = x if recurring_period=='monthly' && recurrence_selector == 1
|
||||
end
|
||||
|
||||
|
|
@ -214,7 +286,7 @@ class RecurringTodo < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def monthly_every_xth_day=(x)
|
||||
self.every_other3 = x if recurring_period=='monthly'
|
||||
self.every_other3 = x if recurring_period=='monthly'
|
||||
end
|
||||
|
||||
def monthly_every_xth_day(default=nil)
|
||||
|
|
@ -318,6 +390,7 @@ class RecurringTodo < ActiveRecord::Base
|
|||
def recurrence_pattern
|
||||
case recurring_period
|
||||
when 'daily'
|
||||
return "invalid repeat pattern" if every_other1.nil?
|
||||
if only_work_days
|
||||
return "on work days"
|
||||
else
|
||||
|
|
@ -328,18 +401,21 @@ class RecurringTodo < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
when 'weekly'
|
||||
return "invalid repeat pattern" if every_other1.nil?
|
||||
if every_other1 > 1
|
||||
return "every #{every_other1} weeks"
|
||||
else
|
||||
return 'weekly'
|
||||
end
|
||||
when 'monthly'
|
||||
return "invalid repeat pattern" if every_other1.nil? || every_other2.nil?
|
||||
if self.recurrence_selector == 0
|
||||
return "every #{self.every_other2} month#{self.every_other2>1?'s':''} on day #{self.every_other1}"
|
||||
else
|
||||
return "every #{self.xth} #{self.day_of_week} of every #{self.every_other2} month#{self.every_other2>1?'s':''}"
|
||||
end
|
||||
when 'yearly'
|
||||
return "invalid repeat pattern" if every_other1.nil?
|
||||
if self.recurrence_selector == 0
|
||||
return "every year on #{self.month_of_year} #{self.every_other1}"
|
||||
else
|
||||
|
|
@ -348,7 +424,7 @@ class RecurringTodo < ActiveRecord::Base
|
|||
else
|
||||
return 'unknown recurrence pattern: period unknown'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def xth
|
||||
xth_day = ['first','second','third','fourth','last']
|
||||
|
|
@ -382,9 +458,9 @@ class RecurringTodo < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def get_show_from_date(previous)
|
||||
case self.target
|
||||
case self.target
|
||||
when 'due_date'
|
||||
# so set show from date relative to due date unless show_always is true or show_from_delta is nil
|
||||
# so set show from date relative to due date unless show_always is true or show_from_delta is nil
|
||||
if self.show_always? or self.show_from_delta.nil?
|
||||
nil
|
||||
else
|
||||
|
|
@ -400,17 +476,17 @@ class RecurringTodo < ActiveRecord::Base
|
|||
|
||||
def get_next_date(previous)
|
||||
case self.recurring_period
|
||||
when 'daily'
|
||||
when 'daily'
|
||||
return get_daily_date(previous)
|
||||
when 'weekly'
|
||||
when 'weekly'
|
||||
return get_weekly_date(previous)
|
||||
when 'monthly'
|
||||
when 'monthly'
|
||||
return get_monthly_date(previous)
|
||||
when 'yearly'
|
||||
return get_yearly_date(previous)
|
||||
else
|
||||
raise Exception.new, "unknown recurrence pattern: '#{self.recurring_period}'"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_daily_date(previous)
|
||||
|
|
@ -430,7 +506,7 @@ class RecurringTodo < ActiveRecord::Base
|
|||
unless self.start_from.nil?
|
||||
# check if the start_from date is later than previous. If so, use
|
||||
# start_from as start to search for next date
|
||||
start = self.start_from if self.start_from > previous
|
||||
start = self.start_from if self.start_from > previous
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -457,7 +533,7 @@ class RecurringTodo < ActiveRecord::Base
|
|||
start = self.start_from.nil? ? Time.zone.now : self.start_from
|
||||
else
|
||||
start = previous + 1.day
|
||||
if start.wday() == 0
|
||||
if start.wday() == 0
|
||||
# we went to a new week , go to the nth next week and find first match
|
||||
# that week
|
||||
start += self.every_other1.week
|
||||
|
|
@ -465,7 +541,7 @@ class RecurringTodo < ActiveRecord::Base
|
|||
unless self.start_from.nil?
|
||||
# check if the start_from date is later than previous. If so, use
|
||||
# start_from as start to search for next date
|
||||
start = self.start_from if self.start_from > previous
|
||||
start = self.start_from if self.start_from > previous
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -483,7 +559,7 @@ class RecurringTodo < ActiveRecord::Base
|
|||
return start + (i-start.wday()).days unless self.every_day[i,1] == ' '
|
||||
end
|
||||
|
||||
raise Exception.new, "unable to find next weekly date (#{self.every_day})"
|
||||
raise Exception.new, "unable to find next weekly date (#{self.every_day})"
|
||||
end
|
||||
|
||||
def get_monthly_date(previous)
|
||||
|
|
@ -531,7 +607,7 @@ class RecurringTodo < ActiveRecord::Base
|
|||
end
|
||||
return the_next
|
||||
else
|
||||
raise Exception.new, "unknown monthly recurrence selection (#{self.recurrence_selector})"
|
||||
raise Exception.new, "unknown monthly recurrence selection (#{self.recurrence_selector})"
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
|
@ -557,7 +633,7 @@ class RecurringTodo < ActiveRecord::Base
|
|||
start+= 1.day
|
||||
end
|
||||
n -= 1
|
||||
start += 1.day unless n==0
|
||||
start += 1.day unless n==0
|
||||
end
|
||||
# convert back to local timezone
|
||||
return Time.zone.local(start.year, start.month, start.day)
|
||||
|
|
@ -574,10 +650,10 @@ class RecurringTodo < ActiveRecord::Base
|
|||
if start.month > month || (start.month == month && start.day >= day)
|
||||
# if there is no next month n and day m in this year, search in next
|
||||
# year
|
||||
start = Time.zone.local(start.year+1, month, 1)
|
||||
start = Time.zone.local(start.year+1, month, 1)
|
||||
else
|
||||
# if there is a next month n, stay in this year
|
||||
start = Time.zone.local(start.year, month, 1)
|
||||
start = Time.zone.local(start.year, month, 1)
|
||||
end
|
||||
return Time.zone.local(start.year, month, day)
|
||||
|
||||
|
|
@ -594,7 +670,7 @@ class RecurringTodo < ActiveRecord::Base
|
|||
|
||||
return the_next
|
||||
else
|
||||
raise Exception.new, "unknown monthly recurrence selection (#{self.recurrence_selector})"
|
||||
raise Exception.new, "unknown monthly recurrence selection (#{self.recurrence_selector})"
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
|
@ -635,10 +711,15 @@ class RecurringTodo < ActiveRecord::Base
|
|||
else
|
||||
_add_tags(Todo::STARRED_TAG_NAME)
|
||||
tags.reload
|
||||
end
|
||||
starred?
|
||||
end
|
||||
starred?
|
||||
end
|
||||
|
||||
def remove_from_project!
|
||||
self.project = nil
|
||||
self.save
|
||||
end
|
||||
|
||||
def inc_occurences
|
||||
self.occurences_count += 1
|
||||
self.save
|
||||
|
|
@ -659,7 +740,7 @@ class RecurringTodo < ActiveRecord::Base
|
|||
unless self.start_from.nil?
|
||||
# check if the start_from date is later than previous. If so, use
|
||||
# start_from as start to search for next date
|
||||
start = self.start_from if self.start_from > previous
|
||||
start = self.start_from if self.start_from > previous
|
||||
end
|
||||
end
|
||||
return start
|
||||
|
|
|
|||
|
|
@ -286,7 +286,15 @@ class Todo < ActiveRecord::Base
|
|||
def active_to_block
|
||||
return successors.find_all {|t| t.active? or t.deferred?}
|
||||
end
|
||||
|
||||
|
||||
def notes=(value)
|
||||
super(value.try(:gsub, /</, '<').try(:gsub, />/, '>'))
|
||||
end
|
||||
|
||||
def raw_notes=(value)
|
||||
self[:notes] = value
|
||||
end
|
||||
|
||||
# Rich Todo API
|
||||
|
||||
def self.from_rich_message(user, default_context_id, description, notes)
|
||||
|
|
@ -324,7 +332,7 @@ class Todo < ActiveRecord::Base
|
|||
|
||||
todo = user.todos.build
|
||||
todo.description = description
|
||||
todo.notes = notes
|
||||
todo.raw_notes = notes
|
||||
todo.context_id = context_id
|
||||
todo.project_id = project_id unless project_id.nil?
|
||||
return todo
|
||||
|
|
|
|||
|
|
@ -16,4 +16,5 @@
|
|||
</div>
|
||||
<%= render :partial => "todos/todo", :collection => @not_done, :locals => { :parent_container_type => "context" } %>
|
||||
</div><!-- [end:items] -->
|
||||
<div id="c_<%=context.id%>_target" class="context_target drop_target"></div>
|
||||
</div><!-- [end:c<%= context.id %>] -->
|
||||
|
|
|
|||
|
|
@ -35,7 +35,8 @@
|
|||
:method => 'get',
|
||||
:with => "'_source_view=#{@source_view}'",
|
||||
:before => "$('#{dom_id(context)}').block({message:null});",
|
||||
:complete => "$('#{dom_id(context)}').unblock();"
|
||||
:complete => "$('#{dom_id(context)}').unblock();",
|
||||
:html => {:id => "edit_context_#{context.id}_link"}
|
||||
) %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<% auth_schemes = Tracks::Config.auth_schemes
|
||||
show_database_form = auth_schemes.include?('database')
|
||||
show_database_form = auth_schemes.include?('database') || auth_schemes.include?('ldap')
|
||||
show_openid_form = auth_schemes.include?('open_id')
|
||||
show_cas_form = auth_schemes.include?('cas')
|
||||
-%>
|
||||
|
|
|
|||
|
|
@ -153,3 +153,5 @@ else
|
|||
page.show 'error_status'
|
||||
page.replace_html 'error_status', "#{error_messages_for('todo')}"
|
||||
end
|
||||
|
||||
page << "enable_rich_interaction();"
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ Rails::Initializer.run do |config|
|
|||
config.gem "RedCloth"
|
||||
config.gem "soap4r", :lib => false
|
||||
config.gem 'datanoise-actionwebservice', :lib => 'actionwebservice'
|
||||
config.gem 'sanitize'
|
||||
|
||||
config.action_controller.use_accept_header = true
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ Then /^he should see that a context named "([^\"]*)" is present$/ do |context_na
|
|||
end
|
||||
|
||||
Then /^he should see that a context named "([^\"]*)" is not present$/ do |context_name|
|
||||
Then "I should not see \"#{context_name}\""
|
||||
Then "I should not see \"#{context_name} (\""
|
||||
end
|
||||
|
||||
Given /^I have a context "([^\"]*)" with (.*) actions$/ do |context_name, number_of_actions|
|
||||
|
|
@ -38,10 +38,16 @@ When /^I delete the context "([^\"]*)"$/ do |context_name|
|
|||
context.should_not be_nil
|
||||
click_link "delete_context_#{context.id}"
|
||||
selenium.get_confirmation.should == "Are you sure that you want to delete the context '#{context_name}'?"
|
||||
wait_for do
|
||||
!selenium.is_element_present("delete_context_#{context.id}")
|
||||
end
|
||||
end
|
||||
|
||||
When /^I edit the context to rename it to "([^\"]*)"$/ do |new_name|
|
||||
click_link "edit_context_#{@context.id}"
|
||||
fill_in "context_name", :with => new_name
|
||||
click_button "submit_context_#{@context.id}"
|
||||
wait_for do
|
||||
selenium.is_visible("flash")
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ Then /the badge should show (.*)/ do |number|
|
|||
badge = -1
|
||||
xpath= "//span[@id='badge_count']"
|
||||
|
||||
if Rails.env == 'selenium'
|
||||
if response.respond_to? :selenium
|
||||
response.should have_xpath(xpath)
|
||||
badge = response.selenium.get_text("xpath=#{xpath}").to_i
|
||||
else
|
||||
|
|
|
|||
|
|
@ -26,8 +26,10 @@ When /^I add note "([^\"]*)" from the "([^\"]*)" project page$/ do |note, projec
|
|||
end
|
||||
|
||||
When /^I delete the first note$/ do
|
||||
title = selenium.get_text("css=div.container h2")
|
||||
id = title.split(' ').last
|
||||
click_link "delete note"
|
||||
selenium.get_confirmation.should == "Are you sure that you want to delete the note '1'?"
|
||||
selenium.get_confirmation.should == "Are you sure that you want to delete the note '#{id}'?"
|
||||
end
|
||||
|
||||
When /^I click the icon next to the note$/ do
|
||||
|
|
@ -53,8 +55,11 @@ Then /^I should see note "([^\"]*)" on the notes page$/ do |note|
|
|||
end
|
||||
|
||||
Then /^the first note should disappear$/ do
|
||||
# the first note contains "A note 1", generated by the Given def above
|
||||
Then "I should not see \"A note 1\""
|
||||
title = selenium.get_text("css=div.container h2")
|
||||
id = title.split(' ').last
|
||||
wait_for :timeout => 15 do
|
||||
!selenium.is_visible("note_#{id}")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ Then /^I should see the bold text "([^\"]*)" in the project description$/ do |bo
|
|||
response.should have_xpath(xpath)
|
||||
bold_text = response.selenium.get_text("xpath=#{xpath}")
|
||||
|
||||
puts "bt=#{bold_text}"
|
||||
bold_text.should =~ /#{bold}/
|
||||
end
|
||||
|
||||
|
|
@ -43,6 +42,5 @@ Then /^I should see the italic text "([^\"]*)" in the project description$/ do |
|
|||
response.should have_xpath(xpath)
|
||||
italic_text = response.selenium.get_text("xpath=#{xpath}")
|
||||
|
||||
puts "it=#{italic_text}"
|
||||
italic_text.should =~ /#{italic}/
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ module LoginSystem
|
|||
end
|
||||
|
||||
def basic_auth_denied
|
||||
response.headers["Status"] = "Unauthorized"
|
||||
response.headers["Status"] = "401 Unauthorized"
|
||||
response.headers["WWW-Authenticate"] = "Basic realm=\"'Tracks Login Required'\""
|
||||
render :text => "401 Unauthorized: You are not authorized to interact with Tracks.", :status => 401
|
||||
end
|
||||
|
|
|
|||
|
|
@ -14,16 +14,14 @@ var TracksForm = {
|
|||
toggleDiv.toggleClass('hide_form');
|
||||
},
|
||||
hide_all_recurring: function () {
|
||||
$('#recurring_daily').hide();
|
||||
$('#recurring_weekly').hide();
|
||||
$('#recurring_monthly').hide();
|
||||
$('#recurring_yearly').hide();
|
||||
$.each(['daily', 'weekly', 'monthly', 'yearly'], function(){
|
||||
$('#recurring_'+this).hide();
|
||||
});
|
||||
},
|
||||
hide_all_edit_recurring: function () {
|
||||
$('#recurring_edit_daily').hide();
|
||||
$('#recurring_edit_weekly').hide();
|
||||
$('#recurring_edit_monthly').hide();
|
||||
$('#recurring_edit_yearly').hide();
|
||||
$.each(['daily', 'weekly', 'monthly', 'yearly'], function(){
|
||||
$('#recurring_edit_'+this).hide();
|
||||
});
|
||||
},
|
||||
toggle_overlay: function () {
|
||||
el = document.getElementById("overlay");
|
||||
|
|
@ -141,6 +139,17 @@ function setup_container_toggles(){
|
|||
|
||||
function askIfNewContextProvided() {
|
||||
var givenContextName = $('#todo_context_name').val();
|
||||
var contextNames = [];
|
||||
var contextNamesRequest = $.ajax({url: relative_to_root('contexts.autocomplete'),
|
||||
async: false,
|
||||
dataType: "text",
|
||||
data: "q="+givenContextName,
|
||||
success: function(result){
|
||||
lines = result.split("\n");
|
||||
for(var i = 0; i < lines.length; i++){
|
||||
contextNames.push(lines[i].split("|")[0]);
|
||||
}
|
||||
}});
|
||||
if (givenContextName.length == 0) return true; // do nothing and depend on rails validation error
|
||||
for (var i = 0; i < contextNames.length; ++i) {
|
||||
if (contextNames[i] == givenContextName) return true;
|
||||
|
|
@ -221,21 +230,46 @@ function enable_rich_interaction(){
|
|||
function drop_todo(evt, ui) {
|
||||
dragged_todo = ui.draggable[0].id.split('_')[2];
|
||||
dropped_todo = $(this).parents('.item-show').get(0).id.split('_')[2];
|
||||
ui.draggable.hide();
|
||||
ui.draggable.remove();
|
||||
$(this).block({message: null});
|
||||
$.post(relative_to_root('todos/add_predecessor'),
|
||||
{successor: dragged_todo, predecessor: dropped_todo},
|
||||
null, 'script');
|
||||
}
|
||||
|
||||
function drag_todo(){
|
||||
$('.drop_target').show();
|
||||
$(this).parents(".container").find(".context_target").hide();
|
||||
}
|
||||
|
||||
$('.item-show').draggable({handle: '.grip',
|
||||
revert: 'invalid',
|
||||
start: function() {$('.successor_target').show();},
|
||||
stop: function() {$('.successor_target').hide();}});
|
||||
start: drag_todo,
|
||||
stop: function() {$('.drop_target').hide();}});
|
||||
|
||||
$('.successor_target').droppable({drop: drop_todo,
|
||||
tolerance: 'pointer',
|
||||
hoverClass: 'hover'});
|
||||
|
||||
/* Drag & drop for changing contexts */
|
||||
function drop_todo_on_context(evt, ui) {
|
||||
target = $(this);
|
||||
dragged_todo = ui.draggable[0].id.split('_')[2];
|
||||
context_id = this.id.split('_')[1];
|
||||
ui.draggable.remove();
|
||||
target.block({message: null});
|
||||
setTimeout(function() {target.show()}, 0);
|
||||
$.post(relative_to_root('todos/update'),
|
||||
{id: dragged_todo,
|
||||
"todo[id]": dragged_todo,
|
||||
"todo[context_id]": context_id},
|
||||
function(){target.unblock(); target.hide();}, 'script');
|
||||
}
|
||||
|
||||
$('.context_target').droppable({
|
||||
drop: drop_todo_on_context,
|
||||
tolerance: 'pointer',
|
||||
hoverClass: 'hover'});
|
||||
|
||||
/* Reset auto updater */
|
||||
field_touched = false;
|
||||
|
|
@ -399,16 +433,12 @@ $(document).ready(function() {
|
|||
TracksForm.toggle_overlay();
|
||||
});
|
||||
$("#recurring_edit_period input").live('click', function(){
|
||||
$.each(['daily', 'weekly', 'monthly', 'yearly'], function(){
|
||||
$('#recurring_edit_'+this).hide();
|
||||
});
|
||||
TracksForm.hide_all_edit_recurring();
|
||||
$('#recurring_edit_'+this.id.split('_')[5]).show();
|
||||
});
|
||||
|
||||
$("#recurring_period input").live('click', function(){
|
||||
$.each(['daily', 'weekly', 'monthly', 'yearly', 'target'], function(){
|
||||
$('#recurring_'+this).hide();
|
||||
});
|
||||
TracksForm.hide_all_recurring();
|
||||
$('#recurring_'+this.id.split('_')[4]).show();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -939,11 +939,14 @@ div.message {
|
|||
cursor: move;
|
||||
}
|
||||
|
||||
.drop_target {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.successor_target {
|
||||
background-image:url("../images/add_successor_off.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center right;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.successor_target.hover {
|
||||
|
|
@ -952,6 +955,15 @@ div.message {
|
|||
background-position: center right;
|
||||
}
|
||||
|
||||
.context_target {
|
||||
height: 15px;
|
||||
margin: 4px;
|
||||
border: thick dotted #CCC;
|
||||
}
|
||||
|
||||
.context_target.hover {
|
||||
}
|
||||
|
||||
/* Error message styles */
|
||||
.fieldWithErrors {
|
||||
padding: 2px;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ require File.dirname(__FILE__) + '/../spec_helper'
|
|||
|
||||
describe MessageGateway do
|
||||
before :each do
|
||||
todo = mock_model(Todo, :description= => nil, :notes= => nil, :context_id= => nil, :save! => nil)
|
||||
todo = mock_model(Todo, :description= => nil, :raw_notes= => nil, :context_id= => nil, :save! => nil)
|
||||
|
||||
@user = mock_model(User,
|
||||
:prefs => mock_model(Preference, :sms_context => mock_model(Context)),
|
||||
|
|
|
|||
18
test/fixtures/contexts.yml
vendored
18
test/fixtures/contexts.yml
vendored
|
|
@ -131,21 +131,3 @@ anothercontext:
|
|||
user_id: 4
|
||||
created_at: <%= today %>
|
||||
updated_at: <%= today %>
|
||||
|
||||
inbox:
|
||||
id: 15
|
||||
name: Inbox
|
||||
position: 1
|
||||
hide: false
|
||||
user_id: 5
|
||||
created_at: <%= today %>
|
||||
updated_at: <%= today %>
|
||||
|
||||
anothercontext:
|
||||
id: 16
|
||||
name: anothercontext
|
||||
position: 2
|
||||
hide: false
|
||||
user_id: 5
|
||||
created_at: <%= today %>
|
||||
updated_at: <%= today %>
|
||||
18
test/fixtures/preferences.yml
vendored
18
test/fixtures/preferences.yml
vendored
|
|
@ -54,21 +54,3 @@ sms_user_prefs:
|
|||
show_project_on_todo_done: true
|
||||
sms_email: 5555555555@tmomail.net
|
||||
sms_context_id: 13
|
||||
|
||||
other_user_prefs:
|
||||
id: 4
|
||||
user_id: 5
|
||||
staleness_starts: 7
|
||||
date_format: "%d/%m/%Y"
|
||||
title_date_format: "%A, %d %B %Y"
|
||||
show_number_completed: 5
|
||||
show_completed_projects_in_sidebar: true
|
||||
show_hidden_contexts_in_sidebar: true
|
||||
show_hidden_projects_in_sidebar: true
|
||||
admin_email: butshesagirl@rousette.org.uk
|
||||
week_starts: 1
|
||||
due_style: 0
|
||||
refresh: 0
|
||||
time_zone: "Los_Angeles"
|
||||
verbose_action_descriptors: false
|
||||
show_project_on_todo_done: true
|
||||
|
|
|
|||
|
|
@ -542,10 +542,9 @@ class TodosControllerTest < ActionController::TestCase
|
|||
def test_format_note_link_message
|
||||
login_as(:admin_user)
|
||||
todo = users(:admin_user).todos.first
|
||||
todo.notes = "A Mail.app message://<ABCDEF-GHADB-123455-FOO-BAR@example.com> link"
|
||||
todo.raw_notes = "A Mail.app message://<ABCDEF-GHADB-123455-FOO-BAR@example.com> link"
|
||||
todo.save!
|
||||
get :index
|
||||
# puts css_select("div#notes_todo_#{todo.id}")
|
||||
assert_select("div#notes_todo_#{todo.id}", 'A Mail.app message://<ABCDEF-GHADB-123455-FOO-BAR@example.com> link')
|
||||
assert_select("div#notes_todo_#{todo.id} a", 'message://<ABCDEF-GHADB-123455-FOO-BAR@example.com>')
|
||||
assert_select("div#notes_todo_#{todo.id} a[href=message://<ABCDEF-GHADB-123455-FOO-BAR@example.com>]", 'message://<ABCDEF-GHADB-123455-FOO-BAR@example.com>')
|
||||
|
|
|
|||
|
|
@ -52,8 +52,9 @@ class UsersControllerTest < ActionController::TestCase
|
|||
def test_destroy_user
|
||||
login_as :admin_user
|
||||
@no_users_before = User.find(:all).size
|
||||
xhr :post, :destroy, :id => users(:ldap_user).id.to_param
|
||||
assert_rjs :page, "user-3", :remove
|
||||
user_id = users(:ldap_user).id
|
||||
xhr :post, :destroy, :id => user_id.to_param
|
||||
assert_rjs :page, "user-#{user_id}", :remove
|
||||
assert_equal @no_users_before-1, User.find(:all).size
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue