class TreesController

File

trees_controller.rb

(C)

Hipposoft 2008

Purpose

Collate data for and send data to the YUI tree plugin.


03-Nov-2009 (ADH): Created.

Public Instance Methods

index() click to toggle source

Respond to XHR requests from the YUI tree handling task selection. See comments inside for details of the required parameters.

# File app/controllers/trees_controller.rb, line 19
def index
  if ( request.xhr? && params.has_key?( :tree_parent_id ) )
    respond_to do | format |
      format.js do

        # Discover the restrictions which apply, if any. Understood keys are:
        #
        #   "inactive"   Returns only inactive projects and tasks. Without
        #                this key, returns only active projects and tasks.
        #
        #   "restrict"   Next array entry must be a user ID. Restricts tasks
        #                to those in the user's task list and projects to
        #                those where at least one of the project tasks are
        #                in the user's task list.
        #
        #   "include"    Next array entry must be one or more underscore-
        #                separated IDs. Only tasks in that list will be
        #                included in the tree. Projects or customers which
        #                end up with no included tasks will not be shown.
        #
        # Note that only tasks permitted by the current user will ever be
        # returned. All the above can do is produce subsets. Attempts to
        # bypass user restrictions by generating custom XHR requests will
        # therefore always fail.

        restrictions  = ( params[ :data ] || '' ).split( ',' )
        index         = 0

        restrict_user = nil
        include_only  = nil
        active        = :active

        until ( restriction = restrictions[ index ] ).nil?
          case restriction

            when 'inactive'
              active = :inactive

            when 'restrict'
              restrict_user = User.find( restrictions[ index + 1 ] )
              index += 1

            when 'include'
              include_only = restrictions[ index + 1 ].split( '_' ).map { | str | str.to_i }
              index += 1

          end
          index += 1
        end

        # Unless the current user is privileged, then always act as if the
        # task list is restricted by them. If the restricted user quoted in
        # the parameters is different then someone is probably trying to hack
        # around with the XHR call! Just override their request.

        restrict_user = @current_user if ( @current_user.restricted? )

        # Find the ID of the parent item selected in the tree. This must have
        # a textual prefix of 'C' or 'P' for Customers or Projects. Tasks
        # should never end up causing a call into this code because they are
        # always leaf nodes.

        id       = params[ :tree_parent_id ]
        children = []

        case id[ 0..0 ]
          when 'C'
            prefix   = 'P'
            isLeaf   = false
            children = Project.send( active ).find_all_by_customer_id( id[ 1..-1 ] )

            # Reject projects if there are no active/inactive tasks; or if we
            # are restricting by a user's permitted task list and the union
            # of the project and user's task list is empty; or if we are
            # restricting by a list of IDs and the union of that list of IDs
            # and the project's task IDs is empty.

            children.reject! do | project |
              project.tasks.send( active ).count.zero? || (
                ( ! restrict_user.nil? ) && ( project.tasks & restrict_user.tasks ).empty?
              ) || (
                ( ! include_only.nil? ) && ( project.task_ids & include_only ).empty?
              )
            end

          when 'P'
            prefix   = ''
            isLeaf   = true
            children = Task.send( active ).find_all_by_project_id( id[ 1..-1 ] )
            children = children & restrict_user.tasks unless ( restrict_user.nil? )

            unless ( include_only.nil? )
              children.reject! do | task |
                not include_only.include?( task.id )
              end
            end

          else
            parent = nil
        end

        if ( children.empty? )
          render :json => []
        else
          children.map!() do | child |
            YuiTree::make_node_object(
              "#{ prefix }#{ child.id }",
              child.title,
              isLeaf,
              ( child.is_a?( Task ) ) ? @@tasks_helper.taskhelp_billable_class( child ) : nil
            )
          end

          render :json => children
        end
      end # format.js do
    end   # respond_to do | format |
  end     # if ( request.xhr? ... )
end