Revision 1297:0a574315af3e .svn/pristine/28

View differences:

.svn/pristine/28/28353268d3c195811c8a35a1db4bfdbe62848deb.svn-base
1
<h4><%= link_to h(document.title), document_path(document) %></h4>
2
<p><em><%= format_time(document.updated_on) %></em></p>
3

  
4
<div class="wiki">
5
  <%= textilizable(truncate_lines(document.description), :object => document) %>
6
</div>
.svn/pristine/28/28460f7863cf0e308a71ddfcfde8f112f06716f0.svn-base
1
module ActiveRecord
2
  module Acts
3
    module Tree
4
      def self.included(base)
5
        base.extend(ClassMethods)
6
      end
7

  
8
      # Specify this +acts_as+ extension if you want to model a tree structure by providing a parent association and a children
9
      # association. This requires that you have a foreign key column, which by default is called +parent_id+.
10
      #
11
      #   class Category < ActiveRecord::Base
12
      #     acts_as_tree :order => "name"
13
      #   end
14
      #
15
      #   Example:
16
      #   root
17
      #    \_ child1
18
      #         \_ subchild1
19
      #         \_ subchild2
20
      #
21
      #   root      = Category.create("name" => "root")
22
      #   child1    = root.children.create("name" => "child1")
23
      #   subchild1 = child1.children.create("name" => "subchild1")
24
      #
25
      #   root.parent   # => nil
26
      #   child1.parent # => root
27
      #   root.children # => [child1]
28
      #   root.children.first.children.first # => subchild1
29
      #
30
      # In addition to the parent and children associations, the following instance methods are added to the class
31
      # after calling <tt>acts_as_tree</tt>:
32
      # * <tt>siblings</tt> - Returns all the children of the parent, excluding the current node (<tt>[subchild2]</tt> when called on <tt>subchild1</tt>)
33
      # * <tt>self_and_siblings</tt> - Returns all the children of the parent, including the current node (<tt>[subchild1, subchild2]</tt> when called on <tt>subchild1</tt>)
34
      # * <tt>ancestors</tt> - Returns all the ancestors of the current node (<tt>[child1, root]</tt> when called on <tt>subchild2</tt>)
35
      # * <tt>root</tt> - Returns the root of the current node (<tt>root</tt> when called on <tt>subchild2</tt>)
36
      module ClassMethods
37
        # Configuration options are:
38
        #
39
        # * <tt>foreign_key</tt> - specifies the column name to use for tracking of the tree (default: +parent_id+)
40
        # * <tt>order</tt> - makes it possible to sort the children according to this SQL snippet.
41
        # * <tt>counter_cache</tt> - keeps a count in a +children_count+ column if set to +true+ (default: +false+).
42
        def acts_as_tree(options = {})
43
          configuration = { :foreign_key => "parent_id", :dependent => :destroy, :order => nil, :counter_cache => nil }
44
          configuration.update(options) if options.is_a?(Hash)
45

  
46
          belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache]
47
          has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => configuration[:dependent]
48

  
49
          class_eval <<-EOV
50
            include ActiveRecord::Acts::Tree::InstanceMethods
51

  
52
            def self.roots
53
              find(:all, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
54
            end
55

  
56
            def self.root
57
              find(:first, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
58
            end
59
          EOV
60
        end
61
      end
62

  
63
      module InstanceMethods
64
        # Returns list of ancestors, starting from parent until root.
65
        #
66
        #   subchild1.ancestors # => [child1, root]
67
        def ancestors
68
          node, nodes = self, []
69
          nodes << node = node.parent while node.parent
70
          nodes
71
        end
72

  
73
        # Returns list of descendants.
74
        #
75
        #   root.descendants # => [child1, subchild1, subchild2]
76
        def descendants(depth=nil)
77
          depth ||= 0
78
          result = children.dup
79
          unless depth == 1
80
            result += children.collect {|child| child.descendants(depth-1)}.flatten
81
          end
82
          result
83
        end
84

  
85
        # Returns list of descendants and a reference to the current node.
86
        #
87
        #   root.self_and_descendants # => [root, child1, subchild1, subchild2]
88
        def self_and_descendants(depth=nil)
89
          [self] + descendants(depth)
90
        end
91

  
92
        # Returns the root node of the tree.
93
        def root
94
          node = self
95
          node = node.parent while node.parent
96
          node
97
        end
98

  
99
        # Returns all siblings of the current node.
100
        #
101
        #   subchild1.siblings # => [subchild2]
102
        def siblings
103
          self_and_siblings - [self]
104
        end
105

  
106
        # Returns all siblings and a reference to the current node.
107
        #
108
        #   subchild1.self_and_siblings # => [subchild1, subchild2]
109
        def self_and_siblings
110
          parent ? parent.children : self.class.roots
111
        end
112
      end
113
    end
114
  end
115
end
.svn/pristine/28/284f5f782295ac4c8fe3dbacfe87f5903171e538.svn-base
1
# Redmine - project management software
2
# Copyright (C) 2006-2012  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
require File.expand_path('../../../test_helper', __FILE__)
19

  
20
class ApiTest::IssueCategoriesTest < ActionController::IntegrationTest
21
  fixtures :projects, :users, :issue_categories, :issues,
22
           :roles,
23
           :member_roles,
24
           :members,
25
           :enabled_modules
26

  
27
  def setup
28
    Setting.rest_api_enabled = '1'
29
  end
30

  
31
  context "GET /projects/:project_id/issue_categories.xml" do
32
    should "return issue categories" do
33
      get '/projects/1/issue_categories.xml', {}, credentials('jsmith')
34
      assert_response :success
35
      assert_equal 'application/xml', @response.content_type
36
      assert_tag :tag => 'issue_categories',
37
        :child => {:tag => 'issue_category', :child => {:tag => 'id', :content => '2'}}
38
    end
39
  end
40

  
41
  context "GET /issue_categories/2.xml" do
42
    should "return requested issue category" do
43
      get '/issue_categories/2.xml', {}, credentials('jsmith')
44
      assert_response :success
45
      assert_equal 'application/xml', @response.content_type
46
      assert_tag :tag => 'issue_category',
47
        :child => {:tag => 'id', :content => '2'}
48
    end
49
  end
50

  
51
  context "POST /projects/:project_id/issue_categories.xml" do
52
    should "return create issue category" do
53
      assert_difference 'IssueCategory.count' do
54
        post '/projects/1/issue_categories.xml', {:issue_category => {:name => 'API'}}, credentials('jsmith')
55
      end
56
      assert_response :created
57
      assert_equal 'application/xml', @response.content_type
58

  
59
      category = IssueCategory.first(:order => 'id DESC')
60
      assert_equal 'API', category.name
61
      assert_equal 1, category.project_id
62
    end
63

  
64
    context "with invalid parameters" do
65
      should "return errors" do
66
        assert_no_difference 'IssueCategory.count' do
67
          post '/projects/1/issue_categories.xml', {:issue_category => {:name => ''}}, credentials('jsmith')
68
        end
69
        assert_response :unprocessable_entity
70
        assert_equal 'application/xml', @response.content_type
71

  
72
        assert_tag 'errors', :child => {:tag => 'error', :content => "Name can't be blank"}
73
      end
74
    end
75
  end
76

  
77
  context "PUT /issue_categories/2.xml" do
78
    context "with valid parameters" do
79
      should "update issue category" do
80
        assert_no_difference 'IssueCategory.count' do
81
          put '/issue_categories/2.xml', {:issue_category => {:name => 'API Update'}}, credentials('jsmith')
82
        end
83
        assert_response :ok
84
        assert_equal '', @response.body
85
        assert_equal 'API Update', IssueCategory.find(2).name
86
      end
87
    end
88

  
89
    context "with invalid parameters" do
90
      should "return errors" do
91
        assert_no_difference 'IssueCategory.count' do
92
          put '/issue_categories/2.xml', {:issue_category => {:name => ''}}, credentials('jsmith')
93
        end
94
        assert_response :unprocessable_entity
95
        assert_equal 'application/xml', @response.content_type
96

  
97
        assert_tag 'errors', :child => {:tag => 'error', :content => "Name can't be blank"}
98
      end
99
    end
100
  end
101

  
102
  context "DELETE /issue_categories/1.xml" do
103
    should "destroy issue categories" do
104
      assert_difference 'IssueCategory.count', -1 do
105
        delete '/issue_categories/1.xml', {}, credentials('jsmith')
106
      end
107
      assert_response :ok
108
      assert_equal '', @response.body
109
      assert_nil IssueCategory.find_by_id(1)
110
    end
111
    
112
    should "reassign issues with :reassign_to_id param" do
113
      issue_count = Issue.count(:conditions => {:category_id => 1})
114
      assert issue_count > 0
115

  
116
      assert_difference 'IssueCategory.count', -1 do
117
        assert_difference 'Issue.count(:conditions => {:category_id => 2})', 3 do
118
          delete '/issue_categories/1.xml', {:reassign_to_id => 2}, credentials('jsmith')
119
        end
120
      end
121
      assert_response :ok
122
      assert_equal '', @response.body
123
      assert_nil IssueCategory.find_by_id(1)
124
    end
125
  end
126
end
.svn/pristine/28/287ad425b706a1e849a16749d3a013cf82f1d342.svn-base
1
# Redmine - project management software
2
# Copyright (C) 2006-2012  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
require File.expand_path('../../../../../test_helper', __FILE__)
19

  
20
class Redmine::Utils::DateCalculationTest < ActiveSupport::TestCase
21
  include Redmine::Utils::DateCalculation
22

  
23
  def test_working_days_without_non_working_week_days
24
    with_settings :non_working_week_days => [] do
25
      assert_working_days 18, '2012-10-09', '2012-10-27'
26
      assert_working_days  6, '2012-10-09', '2012-10-15'
27
      assert_working_days  5, '2012-10-09', '2012-10-14'
28
      assert_working_days  3, '2012-10-09', '2012-10-12'
29
      assert_working_days  3, '2012-10-14', '2012-10-17'
30
      assert_working_days 16, '2012-10-14', '2012-10-30'
31
    end
32
  end
33

  
34
  def test_working_days_with_non_working_week_days
35
    with_settings :non_working_week_days => %w(6 7) do
36
      assert_working_days 14, '2012-10-09', '2012-10-27'
37
      assert_working_days  4, '2012-10-09', '2012-10-15'
38
      assert_working_days  4, '2012-10-09', '2012-10-14'
39
      assert_working_days  3, '2012-10-09', '2012-10-12'
40
      assert_working_days  8, '2012-10-09', '2012-10-19'
41
      assert_working_days  8, '2012-10-11', '2012-10-23'
42
      assert_working_days  2, '2012-10-14', '2012-10-17'
43
      assert_working_days 11, '2012-10-14', '2012-10-30'
44
    end
45
  end
46

  
47
  def test_add_working_days_without_non_working_week_days
48
    with_settings :non_working_week_days => [] do
49
      assert_add_working_days '2012-10-10', '2012-10-10', 0
50
      assert_add_working_days '2012-10-11', '2012-10-10', 1
51
      assert_add_working_days '2012-10-12', '2012-10-10', 2
52
      assert_add_working_days '2012-10-13', '2012-10-10', 3
53
      assert_add_working_days '2012-10-25', '2012-10-10', 15
54
    end
55
  end
56

  
57
  def test_add_working_days_with_non_working_week_days
58
    with_settings :non_working_week_days => %w(6 7) do
59
      assert_add_working_days '2012-10-10', '2012-10-10', 0
60
      assert_add_working_days '2012-10-11', '2012-10-10', 1
61
      assert_add_working_days '2012-10-12', '2012-10-10', 2
62
      assert_add_working_days '2012-10-15', '2012-10-10', 3
63
      assert_add_working_days '2012-10-31', '2012-10-10', 15
64
      assert_add_working_days '2012-10-19', '2012-10-09', 8
65
      assert_add_working_days '2012-10-23', '2012-10-11', 8
66
    end
67
  end
68

  
69
  def assert_working_days(expected_days, from, to)
70
    assert_equal expected_days, working_days(from.to_date, to.to_date)
71
  end
72

  
73
  def assert_add_working_days(expected_date, from, working_days)
74
    assert_equal expected_date.to_date, add_working_days(from.to_date, working_days)
75
  end
76
end
.svn/pristine/28/287b739e36a269ed72c54dcd10ebdefa5f23d6ee.svn-base
1
# Redmine - project management software
2
# Copyright (C) 2006-2012  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
require 'iconv'
19
require 'net/ldap'
20
require 'net/ldap/dn'
21
require 'timeout'
22

  
23
class AuthSourceLdap < AuthSource
24
  validates_presence_of :host, :port, :attr_login
25
  validates_length_of :name, :host, :maximum => 60, :allow_nil => true
26
  validates_length_of :account, :account_password, :base_dn, :filter, :maximum => 255, :allow_blank => true
27
  validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true
28
  validates_numericality_of :port, :only_integer => true
29
  validates_numericality_of :timeout, :only_integer => true, :allow_blank => true
30
  validate :validate_filter
31

  
32
  before_validation :strip_ldap_attributes
33

  
34
  def initialize(attributes=nil, *args)
35
    super
36
    self.port = 389 if self.port == 0
37
  end
38

  
39
  def authenticate(login, password)
40
    return nil if login.blank? || password.blank?
41

  
42
    with_timeout do
43
      attrs = get_user_dn(login, password)
44
      if attrs && attrs[:dn] && authenticate_dn(attrs[:dn], password)
45
        logger.debug "Authentication successful for '#{login}'" if logger && logger.debug?
46
        return attrs.except(:dn)
47
      end
48
    end
49
  rescue Net::LDAP::LdapError => e
50
    raise AuthSourceException.new(e.message)
51
  end
52

  
53
  # test the connection to the LDAP
54
  def test_connection
55
    with_timeout do
56
      ldap_con = initialize_ldap_con(self.account, self.account_password)
57
      ldap_con.open { }
58
    end
59
  rescue Net::LDAP::LdapError => e
60
    raise AuthSourceException.new(e.message)
61
  end
62

  
63
  def auth_method_name
64
    "LDAP"
65
  end
66

  
67
  private
68

  
69
  def with_timeout(&block)
70
    timeout = self.timeout
71
    timeout = 20 unless timeout && timeout > 0
72
    Timeout.timeout(timeout) do
73
      return yield
74
    end
75
  rescue Timeout::Error => e
76
    raise AuthSourceTimeoutException.new(e.message)
77
  end
78

  
79
  def ldap_filter
80
    if filter.present?
81
      Net::LDAP::Filter.construct(filter)
82
    end
83
  rescue Net::LDAP::LdapError
84
    nil
85
  end
86

  
87
  def validate_filter
88
    if filter.present? && ldap_filter.nil?
89
      errors.add(:filter, :invalid)
90
    end
91
  end
92

  
93
  def strip_ldap_attributes
94
    [:attr_login, :attr_firstname, :attr_lastname, :attr_mail].each do |attr|
95
      write_attribute(attr, read_attribute(attr).strip) unless read_attribute(attr).nil?
96
    end
97
  end
98

  
99
  def initialize_ldap_con(ldap_user, ldap_password)
100
    options = { :host => self.host,
101
                :port => self.port,
102
                :encryption => (self.tls ? :simple_tls : nil)
103
              }
104
    options.merge!(:auth => { :method => :simple, :username => ldap_user, :password => ldap_password }) unless ldap_user.blank? && ldap_password.blank?
105
    Net::LDAP.new options
106
  end
107

  
108
  def get_user_attributes_from_ldap_entry(entry)
109
    {
110
     :dn => entry.dn,
111
     :firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname),
112
     :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname),
113
     :mail => AuthSourceLdap.get_attr(entry, self.attr_mail),
114
     :auth_source_id => self.id
115
    }
116
  end
117

  
118
  # Return the attributes needed for the LDAP search.  It will only
119
  # include the user attributes if on-the-fly registration is enabled
120
  def search_attributes
121
    if onthefly_register?
122
      ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail]
123
    else
124
      ['dn']
125
    end
126
  end
127

  
128
  # Check if a DN (user record) authenticates with the password
129
  def authenticate_dn(dn, password)
130
    if dn.present? && password.present?
131
      initialize_ldap_con(dn, password).bind
132
    end
133
  end
134

  
135
  # Get the user's dn and any attributes for them, given their login
136
  def get_user_dn(login, password)
137
    ldap_con = nil
138
    if self.account && self.account.include?("$login")
139
      ldap_con = initialize_ldap_con(self.account.sub("$login", Net::LDAP::DN.escape(login)), password)
140
    else
141
      ldap_con = initialize_ldap_con(self.account, self.account_password)
142
    end
143
    login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
144
    object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
145
    attrs = {}
146

  
147
    search_filter = object_filter & login_filter
148
    if f = ldap_filter
149
      search_filter = search_filter & f
150
    end
151

  
152
    ldap_con.search( :base => self.base_dn,
153
                     :filter => search_filter,
154
                     :attributes=> search_attributes) do |entry|
155

  
156
      if onthefly_register?
157
        attrs = get_user_attributes_from_ldap_entry(entry)
158
      else
159
        attrs = {:dn => entry.dn}
160
      end
161

  
162
      logger.debug "DN found for #{login}: #{attrs[:dn]}" if logger && logger.debug?
163
    end
164

  
165
    attrs
166
  end
167

  
168
  def self.get_attr(entry, attr_name)
169
    if !attr_name.blank?
170
      entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name]
171
    end
172
  end
173
end
.svn/pristine/28/28ad874b5f46ac1b00ddf0031a0a20aed5e4e9c0.svn-base
1
Description:
2
    Generates a plugin model.
3

  
4
Examples:
5
    ./script/rails generate redmine_plugin_model meetings pool

Also available in: Unified diff