phpDocumentor TestlinkAPI
[ class tree: TestlinkAPI ] [ index: TestlinkAPI ] [ all elements ]

Source for file xmlrpc.class.php

Documentation is available at xmlrpc.class.php

  1. <?php
  2. /**
  3.  * TestLink Open Source Project - http://testlink.sourceforge.net/
  4.  * This script is distributed under the GNU General Public License 2 or later.
  5.  *  
  6.  * @filesource     xmlrpc.class.php
  7.  *
  8.  * @author         Asiel Brumfield <asielb@users.sourceforge.net>
  9.  * @package     TestlinkAPI
  10.  * 
  11.  *  Testlink API makes it possible to interact with Testlink
  12.  *  using external applications and services. This makes it possible to report test results
  13.  *  directly from automation frameworks as well as other features.
  14.  * 
  15.  *  See examples for additional detail
  16.  * @example sample_clients/java/org/testlink/api/client/sample/TestlinkAPIXMLRPCClient.java java client sample
  17.  * @example sample_clients/php/clientSample.php php client sample
  18.  * @example sample_clients/ruby/clientSample.rb ruby client sample
  19.  * @example sample_clients/python/clientSample.py python client sample
  20.  * 
  21.  *
  22.  * @internal revisions
  23.  *  20110630 - franciscom - get_linked_versions() interface changes
  24.  *  20110309 - franciscom - BUGID 4311: typo error on uploadExecutionAttachment mapping
  25.  */
  26.  
  27. /** 
  28.  * IXR is the class used for the XML-RPC server
  29.  */
  30. require_once(dirname(__FILE__"/../../third_party/xml-rpc/class-IXR.php");
  31. require_once("api.const.inc.php");
  32. require_once(dirname(__FILE__"/../../config.inc.php");
  33. require_once(dirname(__FILE__"/../functions/common.php");
  34. require_once("APIErrors.php");
  35.  
  36. /**
  37.  * The entry class for serving XML-RPC Requests
  38.  * 
  39.  * See examples for additional detail
  40.  * @example sample_clients/java/org/testlink/api/client/sample/TestlinkAPIXMLRPCClient.java java client sample
  41.  * @example sample_clients/php/clientSample.php php client sample
  42.  * @example sample_clients/ruby/clientSample.rb ruby client sample
  43.  * @example sample_clients/python/clientSample.py python client sample
  44.  * 
  45.  * @author         Asiel Brumfield <asielb@users.sourceforge.net>
  46.  * @package     TestlinkAPI
  47.  * @since         Class available since Release 1.8.0
  48.  * @version     1.0
  49.  */
  50. class TestlinkXMLRPCServer extends IXR_Server
  51. {
  52.     public static $version "1.0";
  53.  
  54.     
  55.     const   OFF=false;
  56.     const   ON=true;
  57.     const   BUILD_GUESS_DEFAULT_MODE=OFF;
  58.     const   SET_ERROR=true;
  59.         
  60.     /**
  61.      * The DB object used throughout the class
  62.      * 
  63.      * @access protected
  64.      */
  65.     protected $dbObj = null;
  66.     protected $tables = null;
  67.  
  68.     protected $tcaseMgr =  null;
  69.     protected $tprojectMgr = null;
  70.     protected $tplanMgr = null;
  71.     protected $reqSpecMgr = null;
  72.     protected $reqMgr = null;
  73.  
  74.     /** Whether the server will run in a testing mode */
  75.     protected $testMode = false;
  76.  
  77.     /** userID associated with the devKey provided */
  78.     protected $userID = null;
  79.     
  80.     /** UserObject associated with the userID */
  81.     protected $user = null;
  82.  
  83.     /** array where all the args are stored for requests */
  84.     protected $args = null;    
  85.  
  86.     /** array where error codes and messages are stored */
  87.     protected $errors = array();
  88.  
  89.     /** The api key being used to make a request */
  90.     protected $devKey = null;
  91.     
  92.     /** boolean to allow a method to invoke another method and avoid double auth */
  93.     protected $authenticated = false;
  94.  
  95.     /** The version of a test case that is being used */
  96.     /** This value is setted in following method:     */
  97.     /** _checkTCIDAndTPIDValid()                      */
  98.     protected $tcVersionID = null;
  99.     protected $versionNumber = null;
  100.     
  101.     
  102.     /**#@+
  103.      * string for parameter names are all defined statically
  104.      * PLEASE define in DICTIONARY ORDER
  105.      * @static
  106.       */
  107.     public static $actionOnDuplicatedNameParamName "actiononduplicatedname";
  108.     public static $activeParamName "active";
  109.     public static $assignedToParamName "assignedto";
  110.     public static $automatedParamName "automated";
  111.     public static $authorLoginParamName "authorlogin";
  112.  
  113.     public static $bugIDParamName "bugid";        
  114.     public static $buildIDParamName "buildid";
  115.     public static $buildNameParamName "buildname";
  116.     public static $buildNotesParamName "buildnotes";
  117.  
  118.     public static $checkDuplicatedNameParamName "checkduplicatedname";
  119.     public static $contentParamName "content";
  120.     public static $customFieldNameParamName "customfieldname";
  121.     public static $customFieldsParamName "customfields";
  122.  
  123.     public static $deepParamName "deep";
  124.     public static $descriptionParamName "description";
  125.     public static $detailsParamName "details";
  126.     public static $devKeyParamName "devKey";
  127.  
  128.     public static $executionIDParamName "executionid";
  129.     public static $executionOrderParamName "executionorder";
  130.     public static $executedParamName "executed";
  131.     public static $executeStatusParamName "executestatus";
  132.     public static $executionTypeParamName "executiontype";
  133.     public static $expectedResultsParamName "expectedresults";
  134.  
  135.     public static $fileNameParamName "filename";
  136.     public static $fileTypeParamName "filetype";
  137.     public static $foreignKeyIdParamName "fkid";
  138.     public static $foreignKeyTableNameParamName "fktable";
  139.  
  140.     public static $guessParamName "guess";
  141.     public static $getStepsInfoParamName "getstepsinfo";
  142.     public static $importanceParamName "importance";
  143.     public static $internalIDParamName "internalid";
  144.     public static $keywordIDParamName "keywordid";
  145.     public static $keywordNameParamName "keywords";
  146.  
  147.     public static $nodeIDParamName "nodeid";
  148.     public static $noteParamName "notes";
  149.  
  150.     public static $optionsParamName "options";
  151.     public static $orderParamName "order";
  152.     public static $overwriteParamName "overwrite";
  153.     public static $parentIDParamName "parentid";        
  154.     public static $platformNameParamName "platformname";
  155.     public static $platformIDParamName "platformid";
  156.     public static $preconditionsParamName "preconditions";
  157.     public static $publicParamName "public";
  158.  
  159.     public static $requirementsParamName "requirements";
  160.  
  161.     public static $summaryParamName "summary";
  162.     public static $statusParamName "status";
  163.     public static $stepsParamName "steps";
  164.  
  165.     public static $testCaseIDParamName "testcaseid";
  166.     public static $testCaseExternalIDParamName "testcaseexternalid";
  167.     public static $testCaseNameParamName "testcasename";
  168.     public static $testCasePathNameParamName "testcasepathname";
  169.     public static $testCasePrefixParamName "testcaseprefix";
  170.     public static $testModeParamName "testmode";
  171.     public static $testPlanIDParamName "testplanid";
  172.     public static $testPlanNameParamName "testplanname";
  173.     public static $testProjectIDParamName "testprojectid";
  174.     public static $testProjectNameParamName "testprojectname";
  175.     public static $testSuiteIDParamName "testsuiteid";
  176.     public static $testSuiteNameParamName "testsuitename";
  177.     public static $timeStampParamName "timestamp";
  178.     public static $titleParamName "title";
  179.  
  180.  
  181.     public static $urgencyParamName "urgency";
  182.     public static $userParamName "user";
  183.  
  184.  
  185.     public static $versionNumberParamName "version";
  186.     
  187.  
  188.  
  189.     // public static $executionRunTypeParamName        = "executionruntype";
  190.         
  191.     
  192.     /**#@-*/
  193.     
  194.     /**
  195.      * An array containing strings for valid statuses
  196.      * Will be initialized using user configuration via config_get()
  197.      */
  198.     public $statusCode;
  199.     public $codeStatus;
  200.   
  201.     
  202.     /**
  203.      * Constructor sets up the IXR_Server and db connection
  204.      */
  205.     public function __construct($callbacks array())
  206.     {        
  207.         $this->dbObj = new database(DB_TYPE);
  208.         $this->dbObj->db->SetFetchMode(ADODB_FETCH_ASSOC);
  209.         $this->_connectToDB();
  210.         
  211.         $this->tcaseMgr=new testcase($this->dbObj);
  212.         $this->tprojectMgr=new testproject($this->dbObj);
  213.         $this->tplanMgr=new testplan($this->dbObj);
  214.         $this->reqSpecMgr=new requirement_spec_mgr($this->dbObj);
  215.         $this->reqMgr=new requirement_mgr($this->dbObj);
  216.         
  217.         $this->tables = $this->tcaseMgr->getDBTables();
  218.         
  219.         $resultsCfg config_get('results');
  220.         foreach($resultsCfg['status_label_for_exec_ui'as $key => $label )
  221.         {
  222.             $this->statusCode[$key]=$resultsCfg['status_code'][$key];  
  223.         }
  224.         
  225.         ifisset($this->statusCode['not_run']) )
  226.         {
  227.             unset($this->statusCode['not_run']);  
  228.         }   
  229.         $this->codeStatus=array_flip($this->statusCode);
  230.         
  231.         
  232.         
  233.         $this->methods array'tl.reportTCResult' => 'this:reportTCResult',
  234.                                 'tl.setTestCaseExecutionResult' => 'this:reportTCResult',
  235.                                 'tl.createBuild' => 'this:createBuild',
  236.                                 'tl.createTestCase' => 'this:createTestCase',
  237.                                 'tl.createTestPlan' => 'this:createTestPlan',
  238.                                 'tl.createTestProject' => 'this:createTestProject',
  239.                                 'tl.createTestSuite' => 'this:createTestSuite',
  240.                                 'tl.uploadExecutionAttachment' => 'this:uploadExecutionAttachment',
  241.                                 'tl.uploadRequirementSpecificationAttachment' => 'this:uploadRequirementSpecificationAttachment',
  242.                                 'tl.uploadRequirementAttachment' => 'this:uploadRequirementAttachment',
  243.                                 'tl.uploadTestProjectAttachment' => 'this:uploadTestProjectAttachment',
  244.                                 'tl.uploadTestSuiteAttachment' => 'this:uploadTestSuiteAttachment',
  245.                                 'tl.uploadTestCaseAttachment' => 'this:uploadTestCaseAttachment',
  246.                                 'tl.uploadAttachment' => 'this:uploadAttachment',
  247.                                 'tl.assignRequirements' => 'this:assignRequirements',     
  248.                                 'tl.addTestCaseToTestPlan' => 'this:addTestCaseToTestPlan',
  249.                                 'tl.getProjects' => 'this:getProjects',
  250.                                 'tl.getTestProjectByName' => 'this:getTestProjectByName',
  251.                                 'tl.getTestPlanByName' => 'this:getTestPlanByName',
  252.                                 'tl.getProjectTestPlans' => 'this:getProjectTestPlans',
  253.                                 'tl.getTestPlanPlatforms' => 'this:getTestPlanPlatforms',
  254.                                 'tl.getTotalsForTestPlan' => 'this:getTotalsForTestPlan',
  255.                                 'tl.getBuildsForTestPlan' => 'this:getBuildsForTestPlan',
  256.                                 'tl.getLatestBuildForTestPlan' => 'this:getLatestBuildForTestPlan',    
  257.                                 'tl.getLastExecutionResult' => 'this:getLastExecutionResult',
  258.                                 'tl.getTestSuitesForTestPlan' => 'this:getTestSuitesForTestPlan',
  259.                                 'tl.getTestSuitesForTestSuite' => 'this:getTestSuitesForTestSuite',
  260.                                 'tl.getTestCasesForTestSuite'    => 'this:getTestCasesForTestSuite',
  261.                                 'tl.getTestCasesForTestPlan' => 'this:getTestCasesForTestPlan',
  262.                                 'tl.getTestCaseIDByName' => 'this:getTestCaseIDByName',
  263.                                 'tl.getTestCaseCustomFieldDesignValue' => 'this:getTestCaseCustomFieldDesignValue',
  264.                                 'tl.getFirstLevelTestSuitesForTestProject' => 'this:getFirstLevelTestSuitesForTestProject',     
  265.                                 'tl.getTestCaseAttachments' => 'this:getTestCaseAttachments',
  266.                                 'tl.getTestCase' => 'this:getTestCase',
  267.                                 'tl.getFullPath' => 'this:getFullPath',
  268.                                 'tl.getTestSuiteByID' => 'this:getTestSuiteByID',
  269.                                 'tl.deleteExecution' => 'this:deleteExecution',
  270.                                 'tl.doesUserExist' => 'this:doesUserExist',
  271.                                 'tl.checkDevKey' => 'this:checkDevKey',
  272.                                 'tl.about' => 'this:about',
  273.                                 'tl.setTestMode' => 'this:setTestMode',
  274.                                 // ping is an alias for sayHello
  275.                                 'tl.ping' => 'this:sayHello'
  276.                                 'tl.sayHello' => 'this:sayHello',
  277.                                 'tl.repeat' => 'this:repeat'
  278.                               );                
  279.         
  280.         $this->methods += $callbacks;
  281.         $this->IXR_Server($this->methods);        
  282.     }    
  283.     
  284.     protected function _setArgs($args)
  285.     {
  286.         // TODO: should escape args
  287.         $this->args = $args;
  288.     }
  289.     
  290.     /**
  291.      * Set the BuildID from one place
  292.      * 
  293.      * @param int $buildID 
  294.      * @access protected
  295.      */
  296.     protected function _setBuildID($buildID)
  297.     {        
  298.         if(GENERAL_ERROR_CODE != $buildID)
  299.         {            
  300.             $this->args[self::$buildIDParamName$buildID;            
  301.             return true;
  302.         }
  303.         else
  304.         {
  305.             $this->errors[new IXR_Error(INVALID_BUILDIDINVALID_BUILDID_STR);
  306.             return false;
  307.         }    
  308.     }
  309.     
  310.     
  311.     /**
  312.      * Set test case internal ID
  313.      * 
  314.      * @param int $tcaseID 
  315.      * @access protected
  316.      */
  317.     protected function _setTestCaseID($tcaseID)
  318.     {        
  319.             $this->args[self::$testCaseIDParamName$tcaseID;            
  320.     }
  321.     
  322.     /**
  323.      * Set Build Id to latest build id (if test plan has builds)
  324.      * 
  325.      * @return boolean 
  326.      * @access protected
  327.      */ 
  328.     protected function _setBuildID2Latest()
  329.     {
  330.         $tplan_id=$this->args[self::$testPlanIDParamName];
  331.         $maxbuildid $this->tplanMgr->get_max_build_id($tplan_id);
  332.         $status_ok=($maxbuildid >0);
  333.         if($status_ok)
  334.         {
  335.             $this->_setBuildID($maxbuildid);  
  336.         
  337.         return $status_ok;
  338.     }    
  339.         
  340.     /**
  341.      * connect to the db and set up the db object
  342.      *
  343.      * @access protected
  344.      *
  345.      * @internal revisions:
  346.      *   20100731 - asimon - BUGID 3644 (additional fix for BUGID 2607)
  347.      *   20100711 - franciscom - BUGID 2607 - UTF8 settings for MySQL
  348.      */        
  349.     protected function _connectToDB()
  350.     {
  351.         if(true == $this->testMode)
  352.         {
  353.             $this->dbObj->connect(TEST_DSNTEST_DB_HOSTTEST_DB_USERTEST_DB_PASSTEST_DB_NAME);
  354.         }
  355.         else
  356.         {
  357.             $this->dbObj->connect(DSNDB_HOSTDB_USERDB_PASSDB_NAME);
  358.         }
  359.         // asimon - BUGID 3644 & 2607 - $charSet was undefined here
  360.         $charSet config_get('charset');
  361.         if((DB_TYPE == 'mysql'&& ($charSet == 'UTF-8'))
  362.         {
  363.             $this->dbObj->exec_query("SET CHARACTER SET utf8");
  364.             $this->dbObj->exec_query("SET collation_connection = 'utf8_general_ci'");
  365.         }
  366.     }
  367.  
  368.     /**
  369.      * authenticates a user based on the devKey provided
  370.      * 
  371.      * This is the only method that should really be used directly to authenticate
  372.      *
  373.      * @param string $messagePrefix used to be prepended to error message
  374.      *
  375.      * @return boolean 
  376.      * @access protected
  377.      */
  378.     protected function authenticate($messagePrefix='')
  379.     {   
  380.                  
  381.         // check that the key was given as part of the args
  382.         if(!$this->_isDevKeyPresent())
  383.         {
  384.             $this->errors[new IXR_ERROR(NO_DEV_KEY$messagePrefix NO_DEV_KEY_STR);
  385.             $this->authenticated = false;
  386.             return false;
  387.         }
  388.         else
  389.         {
  390.             $this->devKey = $this->args[self::$devKeyParamName];
  391.         }
  392.         // make sure the key we have is valid
  393.         if(!$this->_isDevKeyValid($this->devKey))
  394.         {
  395.             $this->errors[new IXR_Error(INVALID_AUTH$messagePrefix INVALID_AUTH_STR);
  396.             $this->authenticated = false;
  397.             return false;            
  398.         }
  399.         else
  400.         {
  401.             //Load User
  402.             $this->user = tlUser::getByID($this->dbObj,$this->userID);    
  403.             $this->authenticated = true;            
  404.             return true;
  405.         }                
  406.     }
  407.     
  408.     
  409.     /**
  410.      * checks if a user has requested right on test project, test plan pair.
  411.      * 
  412.      * @param string $roleQuestion  on of the right defined in rights table
  413.      *
  414.      * @return boolean 
  415.      * @access protected
  416.      */
  417.     protected function userHasRight($roleQuestion)
  418.     {
  419.           $status_ok true;
  420.           $tprojectid $this->args[self::$testProjectIDParamName];
  421.         $tplanid = isset($this->args[self::$testPlanIDParamName]$this->args[self::$testPlanIDParamNamenull;
  422.  
  423.         if(!$this->user->hasRight($this->dbObj,$roleQuestion,$tprojectid$tplanid))
  424.         {
  425.             $status_ok false;
  426.             $this->errors[new IXR_Error(INSUFFICIENT_RIGHTSINSUFFICIENT_RIGHTS_STR);
  427.         }
  428.         return $status_ok;
  429.     }
  430.  
  431.     /**
  432.      * Helper method to see if the testcasename provided is valid
  433.      * 
  434.      * This is the only method that should be called directly to check the testcasename
  435.      *     
  436.      * @return boolean 
  437.      * @access protected
  438.      */        
  439.     protected function checkTestCaseName()
  440.     {
  441.         $status true;
  442.         if(!$this->_isTestCaseNamePresent())
  443.         {
  444.               $this->errors[new IXR_Error(NO_TESTCASENAMENO_TESTCASENAME_STR);
  445.               $status=false;
  446.         }
  447.         else
  448.         {
  449.             $testCaseName $this->args[self::$testCaseNameParamName];
  450.             if(!is_string($testCaseName))
  451.             {
  452.                 $this->errors[new IXR_Error(TESTCASENAME_NOT_STRINGTESTCASENAME_NOT_STRING_STR);
  453.                 $status=false;
  454.             }
  455.         }
  456.         return $status;
  457.     }
  458.     
  459.     /**
  460.      * Helper method to see if the status provided is valid
  461.      * 
  462.      * This is the only method that should be called directly to check the status
  463.      *     
  464.      * @return boolean 
  465.      * @access protected
  466.      */    
  467.     protected function checkStatus()
  468.     {
  469.             if( ($status=$this->_isStatusPresent()) )
  470.             {
  471.                 if!($status=$this->_isStatusValid($this->args[self::$statusParamName])))
  472.                 {
  473.                     // BUGID 3455
  474.                     $msg sprintf(INVALID_STATUS_STR,$this->args[self::$statusParamName]);
  475.                     $this->errors[new IXR_Error(INVALID_STATUS$msg);
  476.                 }        
  477.             }
  478.             else
  479.             {
  480.                 $this->errors[new IXR_Error(NO_STATUSNO_STATUS_STR);
  481.             }
  482.             return $status;
  483.     }       
  484.     
  485.     /**
  486.      * Helper method to see if the tcid provided is valid
  487.      * 
  488.      * This is the only method that should be called directly to check the tcid
  489.      *
  490.      * @param string $messagePrefix used to be prepended to error message
  491.      *
  492.      * @return boolean 
  493.      * @access protected
  494.      */    
  495.     protected function checkTestCaseID($messagePrefix='')
  496.     {
  497.         $msg $messagePrefix;
  498.         $status_ok=$this->_isTestCaseIDPresent();
  499.         if$status_ok)
  500.         {
  501.             $tcaseid $this->args[self::$testCaseIDParamName];
  502.             if(!$this->_isTestCaseIDValid($tcaseid))
  503.             {
  504.                 $this->errors[new IXR_Error(INVALID_TCASEID$msg INVALID_TCASEID_STR);
  505.                 $status_ok=false;
  506.             }
  507.         }        
  508.         else
  509.         {
  510.             $this->errors[new IXR_Error(NO_TCASEID$msg NO_TCASEID_STR);
  511.         }
  512.         return $status_ok;
  513.     }
  514.     
  515.     /**
  516.      * Helper method to see if the tplanid provided is valid
  517.      * 
  518.      * This is the only method that should be called directly to check the tplanid
  519.      *
  520.      * @param string $messagePrefix used to be prepended to error message
  521.      *
  522.      * @return boolean 
  523.      * @access protected
  524.      */    
  525.     protected function checkTestPlanID($messagePrefix='')
  526.     {
  527.         $status=true;
  528.         if(!$this->_isTestPlanIDPresent())
  529.         {
  530.             $msg $messagePrefix NO_TPLANID_STR;
  531.             $this->errors[new IXR_Error(NO_TPLANID$msg);
  532.             $status false;
  533.         }
  534.         else
  535.         {            
  536.             // See if this TPID exists in the db
  537.             $tplanid $this->dbObj->prepare_int($this->args[self::$testPlanIDParamName]);
  538.             $query "SELECT id FROM {$this->tables['testplans']} WHERE id={$tplanid}";
  539.             $result $this->dbObj->fetchFirstRowSingleColumn($query"id");             
  540.             if(null == $result)
  541.             {
  542.                   $msg $messagePrefix sprintf(INVALID_TPLANID_STR,$tplanid);
  543.                   $this->errors[new IXR_Error(INVALID_TPLANID$msg);
  544.                   $status false;                
  545.             }
  546.             else
  547.             {
  548.                  // tplanid exists and its valid
  549.                 // Do we need to try to guess build id ?
  550.                 if$this->checkGuess(&& 
  551.                     (!$this->_isBuildIDPresent(&&  
  552.                      !$this->_isParamPresent(self::$buildNameParamName,$messagePrefix)))
  553.                 {
  554.                     $status $this->_setBuildID2Latest();
  555.                 }
  556.                   
  557.             }                                
  558.         }
  559.         return $status;
  560.     
  561.     
  562.     /**
  563.      * Helper method to see if the TestProjectID provided is valid
  564.      * 
  565.      * This is the only method that should be called directly to check the TestProjectID
  566.      *
  567.      * @param string $messagePrefix used to be prepended to error message
  568.      *
  569.      * @return boolean 
  570.      * @access protected
  571.      */    
  572.     protected function checkTestProjectID($messagePrefix='')
  573.     {
  574.         if(!($status=$this->_isTestProjectIDPresent()))
  575.         {
  576.               $this->errors[new IXR_Error(NO_TESTPROJECTID$messagePrefix NO_TESTPROJECTID_STR);
  577.         }
  578.         else
  579.         {            
  580.             // See if this Test Project ID exists in the db
  581.             $testprojectid $this->dbObj->prepare_int($this->args[self::$testProjectIDParamName]);
  582.             $query "SELECT id FROM {$this->tables['testprojects']} WHERE id={$testprojectid}";
  583.             $result $this->dbObj->fetchFirstRowSingleColumn($query"id");             
  584.             if(null == $result)
  585.             {
  586.                 $msg $messagePrefix sprintf(INVALID_TESTPROJECTID_STR,$testprojectid);
  587.                 $this->errors[new IXR_Error(INVALID_TESTPROJECTID$msg);
  588.                 $status=false;                
  589.             }
  590.         }
  591.         return $status;
  592.     }  
  593.  
  594.     /**
  595.      * Helper method to see if the TestSuiteID provided is valid
  596.      * 
  597.      * This is the only method that should be called directly to check the TestSuiteID
  598.      *
  599.      * @param string $messagePrefix used to be prepended to error message
  600.      *
  601.      * @return boolean 
  602.      * @access protected
  603.      */    
  604.     protected function checkTestSuiteID($messagePrefix='')
  605.     {
  606.         if(!($status=$this->_isTestSuiteIDPresent()))
  607.         {
  608.             $this->errors[new IXR_Error(NO_TESTSUITEID$messagePrefix NO_TESTSUITEID_STR);
  609.         }
  610.         else
  611.         {            
  612.             // See if this Test Suite ID exists in the db
  613.             $tsuiteMgr new testsuite($this->dbObj);
  614.             $node_info $tsuiteMgr->get_by_id($this->args[self::$testSuiteIDParamName]);
  615.             if!($status=!is_null($node_info)) )
  616.               {
  617.                   $msg=$messagePrefix;
  618.                   $msg .= sprintf(INVALID_TESTSUITEID_STR$this->args[self::$testSuiteIDParamName]);
  619.                  $this->errors[new IXR_Error(INVALID_TESTSUITEID$msg);
  620.             }
  621.         }
  622.         return $status;
  623.     }          
  624.  
  625.     /**
  626.      * Helper method to see if the guess is set
  627.      * 
  628.      * This is the only method that should be called directly to check the guess param
  629.      * 
  630.      * Guessing is set to true by default
  631.      * @return boolean 
  632.      * @access protected
  633.      */    
  634.     protected function checkGuess()
  635.     {        
  636.         // if guess is set return its value otherwise return true to guess by default
  637.         return($this->_isGuessPresent($this->args[self::$guessParamNameself::BUILD_GUESS_DEFAULT_MODE);    
  638.     }       
  639.     
  640.     /**
  641.      * Helper method to see if the buildID provided is valid for testplan
  642.      * 
  643.      * if build id has not been provided on call, we can use build name if has been
  644.      * provided.
  645.      *
  646.      * This is the only method that should be called directly to check the buildID
  647.      *     
  648.      * @return boolean 
  649.      * @access protected
  650.      *
  651.      * @internal revision
  652.      *  20100613 - franciscom - BUGID 2845: buildname option in reportTCResult will never be used
  653.      */    
  654.     protected function checkBuildID($msg_prefix)
  655.     {
  656.         $tplan_id=$this->args[self::$testPlanIDParamName];
  657.            $status=true;
  658.            $try_again=false;
  659.           
  660.           // First thing is to know is test plan has any build
  661.           $buildQty $this->tplanMgr->getNumberOfBuilds($tplan_id);
  662.           if$buildQty == 0)
  663.           {
  664.             $status false;
  665.             $tplan_info $this->tplanMgr->get_by_id($tplan_id);
  666.             $msg $msg_prefix sprintf(TPLAN_HAS_NO_BUILDS_STR,$tplan_info['name'],$tplan_info['id']);
  667.             $this->errors[new IXR_Error(TPLAN_HAS_NO_BUILDS,$msg);
  668.           
  669.            
  670.            if$status )
  671.            {
  672.                if(!$this->_isBuildIDPresent())
  673.                {
  674.                 $try_again=true;
  675.                 if($this->_isBuildNamePresent())
  676.                 {
  677.                        $try_again=false;
  678.                        $bname trim($this->args[self::$buildNameParamName]);
  679.                     $buildInfo=$this->tplanMgr->get_build_by_name($tplan_id,$bname)
  680.                        
  681.                     ifis_null($buildInfo) )
  682.                     {
  683.                         $msg $msg_prefix sprintf(BUILDNAME_DOES_NOT_EXIST_STR,$bname);
  684.                         $this->errors[new IXR_Error(BUILDNAME_DOES_NOT_EXIST,$msg);
  685.                            $status=false;
  686.                     }
  687.                     else
  688.                     {    
  689.                         $this->args[self::$buildIDParamName]=$buildInfo['id'];
  690.                     }
  691.                 }
  692.             }
  693.                
  694.                if($try_again)
  695.                {
  696.                 // this means we aren't supposed to guess the buildid
  697.                 if(false == $this->checkGuess())           
  698.                 {
  699.                     $this->errors[new IXR_Error(BUILDID_NOGUESSBUILDID_NOGUESS_STR);
  700.                     $this->errors[new IXR_Error(NO_BUILDIDNO_BUILDID_STR);                
  701.                     $status=false;
  702.                 }
  703.                 else
  704.                 {
  705.                     $setBuildResult $this->_setBuildID2Latest();
  706.                     if(false == $setBuildResult)
  707.                     {
  708.                         $this->errors[new IXR_Error(NO_BUILD_FOR_TPLANIDNO_BUILD_FOR_TPLANID_STR);
  709.                         $status=false;
  710.                     }
  711.                 }
  712.                }
  713.                
  714.                if$status)
  715.                {
  716.                    $buildID $this->dbObj->prepare_int($this->args[self::$buildIDParamName]);
  717.               $buildInfo=$this->tplanMgr->get_build_by_id($tplan_id,$buildID)
  718.               ifis_null($buildInfo) )
  719.               {
  720.                   $tplan_info $this->tplanMgr->get_by_id($tplan_id);
  721.                   $msg sprintf(BAD_BUILD_FOR_TPLAN_STR,$buildID,$tplan_info['name'],$tplan_id);          
  722.                           $this->errors[new IXR_Error(BAD_BUILD_FOR_TPLAN$msg);                
  723.                           $status=false;
  724.               }
  725.             }
  726.            
  727.         return $status;
  728.     }
  729.      
  730.  
  731.     /**
  732.      * Helper method to see if a param is present
  733.      * 
  734.      * @param string $pname parameter name
  735.      * @param string $messagePrefix used to be prepended to error message
  736.      * @param boolean $setError default false
  737.      *                 true: add predefined error code to $this->error[]
  738.      *
  739.      * @return boolean 
  740.      * @access protected
  741.      *
  742.      * 
  743.      */           
  744.     protected function _isParamPresent($pname,$messagePrefix='',$setError=false)
  745.     {
  746.         $status_ok=(isset($this->args[$pname]true false);
  747.         if(!$status_ok && $setError)
  748.         {
  749.             $msg $messagePrefix sprintf(MISSING_REQUIRED_PARAMETER_STR,$pname);
  750.             $this->errors[new IXR_Error(MISSING_REQUIRED_PARAMETER$msg);                      
  751.         }
  752.         return $status_ok;
  753.     }
  754.  
  755.     /**
  756.      * Helper method to see if the status provided is valid
  757.      *     
  758.      * @return boolean 
  759.      * @access protected
  760.      */           
  761.     protected function _isStatusValid($status)
  762.     {
  763.         return(in_array($status$this->statusCode));
  764.     }           
  765.  
  766.     /**
  767.      * Helper method to see if a testcasename is given as one of the arguments
  768.      *     
  769.      * @return boolean 
  770.      * @access protected
  771.      */          
  772.      protected function _isTestCaseNamePresent()
  773.      {
  774.             return (isset($this->args[self::$testCaseNameParamName]true false);
  775.      }
  776.  
  777.     /**
  778.      * Helper method to see if a testcasename is given as one of the arguments
  779.      *     
  780.      * @return boolean 
  781.      * @access protected
  782.      */          
  783.      protected function _isTestCaseExternalIDPresent()
  784.      {
  785.           $status=isset($this->args[self::$testCaseExternalIDParamName]true false;
  786.             return $status;
  787.      }
  788.  
  789.  
  790.     /**
  791.      * Helper method to see if a timestamp is given as one of the arguments
  792.      *     
  793.      * @return boolean 
  794.      * @access protected
  795.      */    
  796.     protected function _isTimeStampPresent()
  797.     {
  798.         return (isset($this->args[self::$timeStampParamName]true false);
  799.     }
  800.  
  801.     /**
  802.      * Helper method to see if a buildID is given as one of the arguments
  803.      *     
  804.      * @return boolean 
  805.      * @access protected
  806.      */    
  807.     protected function _isBuildIDPresent()
  808.     {
  809.         return (isset($this->args[self::$buildIDParamName]true false);
  810.     }
  811.     
  812.     /**
  813.      * Helper method to see if a buildname is given as one of the arguments
  814.      *     
  815.      * @return boolean 
  816.      * @access protected
  817.      */    
  818.     protected function _isBuildNamePresent()
  819.     {                                   
  820.         $status=isset($this->args[self::$buildNameParamName]true false;
  821.         return $status;
  822.     }
  823.     
  824.     /**
  825.      * Helper method to see if build notes are given as one of the arguments
  826.      *     
  827.      * @return boolean 
  828.      * @access protected
  829.      */    
  830.     protected function _isBuildNotePresent()
  831.     {
  832.         return (isset($this->args[self::$buildNotesParamName]true false);
  833.     }
  834.     
  835.     /**
  836.      * Helper method to see if testsuiteid is given as one of the arguments
  837.      *     
  838.      * @return boolean 
  839.      * @access protected
  840.      */    
  841.     protected function _isTestSuiteIDPresent()
  842.     {
  843.         return (isset($this->args[self::$testSuiteIDParamName]true false);
  844.     }    
  845.     
  846.     /**
  847.      * Helper method to see if a note is given as one of the arguments
  848.      *     
  849.      * @return boolean 
  850.      * @access protected
  851.      */    
  852.     protected function _isNotePresent()
  853.     {
  854.         return (isset($this->args[self::$noteParamName]true false);
  855.     }        
  856.     
  857.     /**
  858.      * Helper method to see if a tplanid is given as one of the arguments
  859.      *     
  860.      * @return boolean 
  861.      * @access protected
  862.      */    
  863.     protected function _isTestPlanIDPresent()
  864.     {        
  865.         return (isset($this->args[self::$testPlanIDParamName]true false);        
  866.     }
  867.  
  868.     /**
  869.      * Helper method to see if a TestProjectID is given as one of the arguments
  870.      *     
  871.      * @return boolean 
  872.      * @access protected
  873.      */    
  874.     protected function _isTestProjectIDPresent()
  875.     {        
  876.         return (isset($this->args[self::$testProjectIDParamName]true false);        
  877.     }        
  878.     
  879.     /**
  880.      * Helper method to see if automated is given as one of the arguments
  881.      *     
  882.      * @return boolean 
  883.      * @access protected
  884.      */    
  885.     protected function _isAutomatedPresent()
  886.     {        
  887.         return (isset($this->args[self::$automatedParamName]true false);        
  888.     }        
  889.     
  890.     /**
  891.      * Helper method to see if testMode is given as one of the arguments
  892.      *     
  893.      * @return boolean 
  894.      * @access protected
  895.      */    
  896.     protected function _isTestModePresent()
  897.     {
  898.         return (isset($this->args[self::$testModeParamName]true false);      
  899.     }
  900.     
  901.     /**
  902.      * Helper method to see if a devKey is given as one of the arguments
  903.      *      
  904.      * @return boolean 
  905.      * @access protected
  906.      */
  907.     protected function _isDevKeyPresent()
  908.     {
  909.         return (isset($this->args[self::$devKeyParamName]true false);
  910.     }
  911.     
  912.     /**
  913.      * Helper method to see if a tcid is given as one of the arguments
  914.      *     
  915.      * @return boolean 
  916.      * @access protected
  917.      */
  918.     protected function _isTestCaseIDPresent()
  919.     {
  920.         return (isset($this->args[self::$testCaseIDParamName]true false);
  921.     }  
  922.     
  923.     /**
  924.      * Helper method to see if the guess param is given as one of the arguments
  925.      *     
  926.      * @return boolean 
  927.      * @access protected
  928.      */
  929.     protected function _isGuessPresent()
  930.     {
  931.         $status=isset($this->args[self::$guessParamName]true false;
  932.         return $status;
  933.     }
  934.     
  935.     /**
  936.      * Helper method to see if the testsuitename param is given as one of the arguments
  937.      *     
  938.      * @return boolean 
  939.      * @access protected
  940.      */
  941.     protected function _isTestSuiteNamePresent()
  942.     {
  943.             return (isset($this->args[self::$testSuiteNameParamName]true false);
  944.     }    
  945.     
  946.     /**
  947.      * Helper method to see if the deep param is given as one of the arguments
  948.      *     
  949.      * @return boolean 
  950.      * @access protected
  951.      */
  952.     protected function _isDeepPresent()
  953.     {
  954.         return (isset($this->args[self::$deepParamName]true false);
  955.     }      
  956.     
  957.     /**
  958.      * Helper method to see if the status param is given as one of the arguments
  959.      *     
  960.      * @return boolean 
  961.      * @access protected
  962.      */
  963.     protected function _isStatusPresent()
  964.     {
  965.         return (isset($this->args[self::$statusParamName]true false);
  966.     }      
  967.     
  968.     /**
  969.      * Helper method to see if the tcid provided is valid
  970.      *     
  971.      * @param struct $tcaseid 
  972.      * @param string $messagePrefix used to be prepended to error message
  973.      * @param boolean $setError default false
  974.      *                 true: add predefined error code to $this->error[]
  975.      * @return boolean 
  976.      * @access protected
  977.      */
  978.     protected function _isTestCaseIDValid($tcaseid,$messagePrefix='',$setError=false)
  979.     {
  980.         $status_ok=is_numeric($tcaseid);
  981.         if($status_ok)
  982.         {
  983.             // must be of type 'testcase' and show up in the nodes_hierarchy        
  984.             $tcaseid $this->dbObj->prepare_int($tcaseid);
  985.             $query " SELECT NH.id AS id " .
  986.                      " FROM {$this->tables['nodes_hierarchy']} NH, .
  987.                      " {$this->tables['node_types']} NT .
  988.                      " WHERE NH.id={$tcaseid} AND node_type_id=NT.id .
  989.                      " AND NT.description='testcase'";
  990.             $result $this->dbObj->fetchFirstRowSingleColumn($query"id");
  991.             $status_ok is_null($resultfalse true
  992.         }
  993.         else if($setError)
  994.         {
  995.             $this->errors[new IXR_Error(TCASEID_NOT_INTEGER
  996.                                             $messagePrefix TCASEID_NOT_INTEGER_STR);
  997.         }
  998.           return $status_ok;
  999.     }    
  1000.     
  1001.     /**
  1002.      * Helper method to see if a devKey is valid
  1003.      *     
  1004.      * @param string $devKey 
  1005.      * @return boolean 
  1006.      * @access protected
  1007.      */    
  1008.     protected function _isDevKeyValid($devKey)
  1009.     {                           
  1010.         if(null == $devKey || "" == $devKey)
  1011.         {
  1012.             return false;
  1013.         }
  1014.         else
  1015.         {   
  1016.             $this->userID = null;
  1017.             $this->devKey = $this->dbObj->prepare_string($devKey);
  1018.             $query "SELECT id FROM {$this->tables['users']} WHERE script_key='{$this->devKey}'";
  1019.             $this->userID = $this->dbObj->fetchFirstRowSingleColumn($query"id");
  1020.                     
  1021.             if(null == $this->userID)
  1022.             {
  1023.                 return false;                
  1024.             }
  1025.             else
  1026.             {
  1027.                 return true;
  1028.             }
  1029.         }                        
  1030.     }    
  1031.  
  1032.     /**
  1033.      * Helper method to set the tcVersion
  1034.      * 
  1035.      *          
  1036.      * @return boolean
  1037.      * @access protected
  1038.      */        
  1039.     protected function _setTCVersion()
  1040.     {
  1041.         // TODO: Implement
  1042.     }
  1043.     
  1044.     /**
  1045.      * Helper method to See if the tcid and tplanid are valid together 
  1046.      * 
  1047.      * @param map $platformInfo key: platform ID
  1048.      * @param string $messagePrefix used to be prepended to error message
  1049.      * @return boolean
  1050.      * @access protected
  1051.      */            
  1052.     protected function _checkTCIDAndTPIDValid($platformInfo=null,$messagePrefix='')
  1053.     {      
  1054.         $tplan_id = $this->args[self::$testPlanIDParamName];
  1055.         $tcase_id = $this->args[self::$testCaseIDParamName];
  1056.         $platform_id = !is_null($platformInfo) ? key($platformInfo) : null;
  1057.         
  1058.         $filters = array('exec_status' => "ALL", 'active_status' => "ALL",
  1059.                          'tplan_id' => $tplan_id, 'platform_id' => $platform_id);
  1060.         $info = $this->tcaseMgr->get_linked_versions($tcase_id,$filters);
  1061.         $status_ok = !is_null($info);
  1062.         
  1063.                 
  1064.         if( $status_ok )
  1065.         {
  1066.             $this->tcVersionID = key($info);
  1067.             $dummy = current($info);
  1068.             $plat = is_null($platform_id) ? 0 : $platform_id; 
  1069.             $this->versionNumber = $dummy[$tplan_id][$plat]['version'];
  1070.             
  1071.             // $this->errors[] = $this->tcVersionID;
  1072.             // $this->errors[] = $this->versionNumber;
  1073.             // $status_ok = false;    
  1074.         }
  1075.         else
  1076.         {
  1077.             $tplan_info = $this->tplanMgr->get_by_id($tplan_id);
  1078.             $tcase_info = $this->tcaseMgr->get_by_id($tcase_id);
  1079.             
  1080.             if( is_null($platform_id) )
  1081.             {
  1082.                 $msg = sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#defineTCASEID_NOT_IN_TPLANID_STR">TCASEID_NOT_IN_TPLANID_STR</a>,$tcase_info[0]['name'],
  1083.                                $this->args[self::$testCaseExternalIDParamName],$tplan_info['name'],$tplan_id);          
  1084.                 $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineTCASEID_NOT_IN_TPLANID">TCASEID_NOT_IN_TPLANID</a>, $msg);
  1085.             }
  1086.             else
  1087.             {
  1088.                 
  1089.                 $msg = sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#defineTCASEID_NOT_IN_TPLANID_FOR_PLATFORM_STR">TCASEID_NOT_IN_TPLANID_FOR_PLATFORM_STR</a>,$tcase_info[0]['name'],
  1090.                                $this->args[self::$testCaseExternalIDParamName],
  1091.                                $tplan_info['name'],$tplan_id,$platformInfo[$platform_id],$platform_id);          
  1092.                 $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineTCASEID_NOT_IN_TPLANID_FOR_PLATFORM">TCASEID_NOT_IN_TPLANID_FOR_PLATFORM</a>, $msg);
  1093.             }
  1094.         }
  1095.         return $status_ok;      
  1096.     }
  1097.  
  1098.     /**
  1099.      * Run all the necessary checks to see if the createBuild request is valid
  1100.      *  
  1101.      * @param string $messagePrefix used to be prepended to error message
  1102.      * @return boolean
  1103.      * @access protected
  1104.      */
  1105.     protected function _checkCreateBuildRequest($messagePrefix='')
  1106.     {        
  1107.         
  1108.         $checkFunctions = array('authenticate','checkTestPlanID');
  1109.         $status_ok=$this->_runChecks($checkFunctions,$messagePrefix);
  1110.         if($status_ok)
  1111.         {
  1112.             $status_ok=$this->_isParamPresent(self::$buildNameParamName,$messagePrefix,self::SET_ERROR);            
  1113.         }       
  1114.         
  1115.         return $status_ok;
  1116.     }    
  1117.     
  1118.     /**
  1119.      * Run all the necessary checks to see if the createBuild request is valid
  1120.      *  
  1121.      * @return boolean
  1122.      * @access protected
  1123.      */
  1124.     protected function _checkGetBuildRequest()
  1125.     {        
  1126.         $checkFunctions = array('authenticate','checkTestPlanID');       
  1127.         $status_ok=$this->_runChecks($checkFunctions);       
  1128.         return $status_ok;
  1129.     }
  1130.  
  1131.     
  1132.     /**
  1133.      * Run a set of functions 
  1134.      * @param array $checkFunctions set of function to be runned
  1135.      * @param string $messagePrefix used to be prepended to error message
  1136.      *
  1137.      * @return boolean
  1138.      * @access protected
  1139.      */
  1140.     protected function _runChecks($checkFunctions,$messagePrefix='')
  1141.     {
  1142.       foreach($checkFunctions as $pfn)
  1143.       {
  1144.           if( !($status_ok = $this->$pfn($messagePrefix)) )
  1145.           {
  1146.               break; 
  1147.           }
  1148.       } 
  1149.         return $status_ok;
  1150.     }
  1151.  
  1152.  
  1153.  
  1154.     /**
  1155.      * Gets the latest build by choosing the maximum build id for a specific test plan 
  1156.      *
  1157.      * @param struct $args
  1158.      * @param string $args["devKey"]
  1159.      * @param int $args["tplanid"]
  1160.      * @return mixed 
  1161.      *                 
  1162.      * @access public
  1163.      */        
  1164.     public function getLatestBuildForTestPlan($args)
  1165.     {
  1166.         $operation=__FUNCTION__;
  1167.          $msg_prefix="({$operation}) - ";
  1168.         $status_ok=true;
  1169.         $this->_setArgs($args);
  1170.         $resultInfo=array();
  1171.  
  1172.         $checkFunctions = array('authenticate','checkTestPlanID');       
  1173.         $status_ok=$this->_runChecks($checkFunctions,$msg_prefix);       
  1174.  
  1175.         if( $status_ok )
  1176.         {
  1177.             $testPlanID = $this->args[self::$testPlanIDParamName];
  1178.             $build_id = $this->tplanMgr->get_max_build_id($testPlanID);
  1179.          
  1180.             if( ($status_ok=$build_id > 0) )
  1181.             {
  1182.                 $builds = $this->tplanMgr->get_builds($testPlanID);  
  1183.                 $build_info = $builds[$build_id];
  1184.             }
  1185.             else
  1186.             {
  1187.                 $tplan_info=$this->tplanMgr->get_by_id($testPlanID);
  1188.                 $msg = $msg_prefix . sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#defineTPLAN_HAS_NO_BUILDS_STR">TPLAN_HAS_NO_BUILDS_STR</a>,$tplan_info['name'],$tplan_info['id']);
  1189.                 $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineTPLAN_HAS_NO_BUILDS">TPLAN_HAS_NO_BUILDS</a>,$msg);
  1190.             }
  1191.         }
  1192.         
  1193.         return $status_ok ? $build_info : $this->errors;
  1194.     }
  1195.  
  1196.  
  1197.  
  1198.  
  1199.  
  1200.     /**
  1201.      * _getLatestBuildForTestPlan
  1202.      *
  1203.      * @param struct $args
  1204.      *
  1205.      */
  1206.     protected function _getLatestBuildForTestPlan($args)
  1207.     {
  1208.         $builds = $this->_getBuildsForTestPlan($args);
  1209.         $maxid = -1;
  1210.         $maxkey = -1;
  1211.         foreach ($builds as $key => $build) {
  1212.             if ($build['id'] > $maxid)
  1213.             {
  1214.                 $maxkey = $key;
  1215.                 $maxid = $build['id'];
  1216.             }
  1217.         }
  1218.         $maxbuild = array();
  1219.         $maxbuild[] = $builds[$maxkey];
  1220.  
  1221.         return $maxbuild;
  1222.     }
  1223.     
  1224.     /**
  1225.      * Gets the result of LAST EXECUTION for a particular testcase 
  1226.      * on a test plan, but WITHOUT checking for a particular build
  1227.      *
  1228.      * @param struct $args
  1229.      * @param string $args["devKey"]
  1230.      * @param int $args["tplanid"]
  1231.      * @param int $args["testcaseid"]: optional, if does not is present           
  1232.      *                                 testcaseexternalid must be present
  1233.      *
  1234.      * @param int $args["testcaseexternalid"]: optional, if does not is present           
  1235.      *                                         testcaseid must be present
  1236.      *
  1237.      * @return mixed $resultInfo
  1238.      *               if execution found, array with these keys:
  1239.      *               id (execution id),build_id,tester_id,execution_ts,
  1240.      *               status,testplan_id,tcversion_id,tcversion_number,
  1241.      *               execution_type,notes.
  1242.      *
  1243.      *               if test case has not been execute,
  1244.      *               array('id' => -1)
  1245.      *
  1246.      * @access public
  1247.      */
  1248.     public function getLastExecutionResult($args)
  1249.     {
  1250.         $operation=__FUNCTION__;
  1251.          $msg_prefix="({$operation}) - ";
  1252.         
  1253.         $this->_setArgs($args);
  1254.         $resultInfo = array();
  1255.         $status_ok=true;
  1256.                 
  1257.         // Checks are done in order
  1258.         $checkFunctions = array('authenticate','checkTestPlanID','checkTestCaseIdentity');
  1259.  
  1260.         $status_ok=$this->_runChecks($checkFunctions,$msg_prefix) && 
  1261.                    $this->_checkTCIDAndTPIDValid(null,$msg_prefix) &&
  1262.                    $this->userHasRight("mgt_view_tc");       
  1263.  
  1264.         if( $status_ok )
  1265.         {
  1266.             // get all, then return last
  1267.             $sql = " SELECT * FROM {$this->tables['executions'].
  1268.                    " WHERE testplan_id = {$this->args[self::$testPlanIDParamName].
  1269.                    " AND tcversion_id IN (" .
  1270.                    " SELECT id FROM {$this->tables['nodes_hierarchy'].
  1271.                    " WHERE parent_id = {$this->args[self::$testCaseIDParamName]}).
  1272.                    " ORDER BY id DESC";
  1273.                    
  1274.             $result = $this->dbObj->fetchFirstRow($sql);
  1275.  
  1276.             if(null == $result)
  1277.             {
  1278.                // has not been executed
  1279.                // execution id = -1 => test case has not been runned.
  1280.                $resultInfo[]=array('id' => -1);
  1281.             } 
  1282.             else
  1283.             {
  1284.                $resultInfo[]=$result;  
  1285.             }
  1286.         }
  1287.         
  1288.         return $status_ok ? $resultInfo : $this->errors;
  1289.     }
  1290.  
  1291.  
  1292.  
  1293.  
  1294.      /**
  1295.      * Adds the result to the database 
  1296.      *
  1297.      * @return int
  1298.      * @access protected
  1299.      */            
  1300.     protected function _insertResultToDB()
  1301.     {
  1302.         $build_id = $this->args[self::$buildIDParamName];
  1303.         $tester_id =  $this->userID;
  1304.         $status = $this->args[self::$statusParamName];
  1305.         $testplan_id =    $this->args[self::$testPlanIDParamName];
  1306.         $tcversion_id =    $this->tcVersionID;
  1307.         $version_number =    $this->versionNumber;
  1308.  
  1309.         $db_now=$this->dbObj->db_now();
  1310.         $platform_id = 0;
  1311.         
  1312.         if( isset($this->args[self::$platformIDParamName]) )
  1313.         {
  1314.             $platform_id = $this->args[self::$platformIDParamName];     
  1315.         }
  1316.         
  1317.         $notes='';
  1318.         $notes_field="";
  1319.         $notes_value="";  
  1320.  
  1321.         if($this->_isNotePresent())
  1322.         {
  1323.             $notes = $this->dbObj->prepare_string($this->args[self::$noteParamName]);
  1324.         }
  1325.         
  1326.         if(trim($notes) != "")
  1327.         {
  1328.             $notes_field = ",notes";
  1329.             $notes_value = ", '{$notes}'";  
  1330.         }
  1331.         
  1332.         $execution_type = constant("TESTCASE_EXECUTION_TYPE_AUTO");
  1333.  
  1334.         $query = "INSERT INTO {$this->tables['executions'].
  1335.                  " (build_id, tester_id, execution_ts, status, testplan_id, tcversion_id, " .
  1336.                  " platform_id, tcversion_number," .
  1337.                  " execution_type {$notes_field} ) .
  1338.                  " VALUES({$build_id},{$tester_id},{$db_now},'{$status}',{$testplan_id},.
  1339.                  {$tcversion_id},{$platform_id}, {$version_number},{$execution_type{$notes_value})";
  1340.  
  1341.         $this->dbObj->exec_query($query);
  1342.         return $this->dbObj->insert_id($this->tables['executions']);        
  1343.     }
  1344.     
  1345.     
  1346.     /**
  1347.      * Lets you see if the server is up and running
  1348.      *  
  1349.      * @param struct not used    
  1350.      * @return string "Hello!"
  1351.      * @access public
  1352.      */
  1353.     public function sayHello($args)
  1354.     {
  1355.         return 'Hello!';
  1356.     }
  1357.  
  1358.     /**
  1359.      * Repeats a message back 
  1360.      *
  1361.      * @param struct $args should contain $args['str'] parameter
  1362.      * @return string
  1363.      * @access public
  1364.      */    
  1365.     public function repeat($args)
  1366.     {
  1367.         $this->_setArgs($args);
  1368.         $str = "You said: " . $this->args['str'];
  1369.         return $str;
  1370.     }
  1371.  
  1372.     /**
  1373.      * Gives basic information about the API
  1374.      *
  1375.      * @param struct not used
  1376.      * @return string
  1377.      * @access public
  1378.      */    
  1379.     public function about($args)
  1380.     {
  1381.         $this->_setArgs($args);
  1382.         $str = " Testlink API Version: " . self::$version . " initially written by Asiel Brumfield\n" .
  1383.                " with contributions by TestLink development Team";
  1384.         return $str;                
  1385.     }
  1386.     
  1387.     /**
  1388.      * Creates a new build for a specific test plan
  1389.      *
  1390.      * @param struct $args
  1391.      * @param string $args["devKey"]
  1392.      * @param int $args["testplanid"]
  1393.      * @param string $args["buildname"];
  1394.      * @param string $args["buildnotes"];
  1395.      * @return mixed $resultInfo
  1396.      *                 
  1397.      * @access public
  1398.      */        
  1399.     public function createBuild($args)
  1400.     {
  1401.         $operation = __FUNCTION__;
  1402.         $messagePrefix="({$operation}) - ";
  1403.         $resultInfo = array();
  1404.         $resultInfo[0]["status"] = true;
  1405.         $resultInfo[0]["operation"] = $operation;
  1406.         $insertID = '';
  1407.         $returnMessage = <a href="../TestlinkAPI/_APIErrors.php.html#defineGENERAL_SUCCESS_STR">GENERAL_SUCCESS_STR</a>;
  1408.  
  1409.         $this->_setArgs($args);
  1410.  
  1411.         // check the tpid
  1412.         if($this->_checkCreateBuildRequest($messagePrefix) && 
  1413.            $this->userHasRight("testplan_create_build"))
  1414.         {
  1415.             $testPlanID = $this->args[self::$testPlanIDParamName];
  1416.             $buildName = $this->args[self::$buildNameParamName];                    
  1417.             $buildNotes = "";
  1418.             if($this->_isBuildNotePresent())
  1419.             {            
  1420.                 $buildNotes = $this->dbObj->prepare_string($this->args[self::$buildNotesParamName]);
  1421.             }
  1422.             
  1423.             
  1424.             if ($this->tplanMgr->check_build_name_existence($testPlanID,$buildName))
  1425.             {
  1426.                 //Build exists so just get the id of the existing build
  1427.                 $insertID = $this->tplanMgr->get_build_id_by_name($testPlanID,$buildName);
  1428.                 $returnMessage = sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#defineBUILDNAME_ALREADY_EXISTS_STR">BUILDNAME_ALREADY_EXISTS_STR</a>,$buildName,$insertID);
  1429.                 $resultInfo[0]["status"] = false;
  1430.             
  1431.             } else {
  1432.                 //Build doesn't exist so create one
  1433.                 // ,$active=1,$open=1);
  1434.                 $insertID = $this->tplanMgr->create_build($testPlanID,$buildName,$buildNotes);
  1435.             }
  1436.             
  1437.             $resultInfo[0]["id"] = $insertID;    
  1438.             $resultInfo[0]["message"] = $returnMessage;
  1439.             return $resultInfo;                 
  1440.         }
  1441.         else
  1442.         {
  1443.             return $this->errors;
  1444.         }    
  1445.     }
  1446.     
  1447.     /**
  1448.      * Gets a list of all projects
  1449.      * @param struct $args
  1450.      * @param string $args["devKey"]
  1451.      * @return mixed $resultInfo            
  1452.      * @access public
  1453.      */        
  1454.     public function getProjects($args)
  1455.     {
  1456.         $this->_setArgs($args);        
  1457.         //TODO: NEED associated RIGHT
  1458.         if($this->authenticate())
  1459.         {
  1460.             return $this->tprojectMgr->get_all();    
  1461.         }
  1462.         else
  1463.         {
  1464.             return $this->errors;
  1465.         }
  1466.     }
  1467.     
  1468.     /**
  1469.      * Gets a list of test plans within a project
  1470.      *
  1471.      * @param struct $args
  1472.      * @param string $args["devKey"]
  1473.      * @param int $args["testprojectid"]
  1474.      * @return mixed $resultInfo
  1475.      *                 
  1476.      * @access public
  1477.      */        
  1478.     public function getProjectTestPlans($args)
  1479.     {
  1480.         $messagePrefix="(" .__FUNCTION__ . ") - ";
  1481.         
  1482.         $this->_setArgs($args);
  1483.         // check the tplanid
  1484.         //TODO: NEED associated RIGHT
  1485.         $checkFunctions = array('authenticate','checkTestProjectID');       
  1486.         $status_ok=$this->_runChecks($checkFunctions,$messagePrefix);       
  1487.     
  1488.         if($status_ok)
  1489.         {
  1490.             $testProjectID = $this->args[self::$testProjectIDParamName];
  1491.             $info=$this->tprojectMgr->get_all_testplans($testProjectID);
  1492.             if( !is_null($info) && count($info) > 0 )
  1493.             {
  1494.                 $info = array_values($info);
  1495.             }
  1496.             return $info;    
  1497.         }
  1498.         else
  1499.         {
  1500.             return $this->errors;
  1501.         } 
  1502.     }
  1503.     
  1504.     /**
  1505.      * Gets a list of builds within a test plan
  1506.      *
  1507.      * @param struct $args
  1508.      * @param string $args["devKey"]
  1509.      * @param int $args["testplanid"]
  1510.      * @return 
  1511.      *         if no errors
  1512.      *            no build present => null
  1513.      *            array of builds
  1514.      *         
  1515.      *                 
  1516.      * @access public
  1517.      */        
  1518.     public function getBuildsForTestPlan($args)
  1519.     {
  1520.         $operation=__FUNCTION__;
  1521.          $msg_prefix="({$operation}) - ";
  1522.         $this->_setArgs($args);
  1523.  
  1524.         $builds=null;
  1525.         $status_ok=true;
  1526.         $checkFunctions = array('authenticate','checkTestPlanID');       
  1527.         $status_ok=$this->_runChecks($checkFunctions,$msg_prefix);       
  1528.       
  1529.         if( $status_ok )
  1530.         {
  1531.             $testPlanID = $this->args[self::$testPlanIDParamName];
  1532.             $dummy = $this->tplanMgr->get_builds($testPlanID);
  1533.                   
  1534.               if( !is_null($dummy) )
  1535.               {
  1536.                  $builds=array_values($dummy);
  1537.               }
  1538.         }
  1539.         return $status_ok ? $builds : $this->errors;
  1540.     }
  1541.  
  1542.  
  1543.     /**
  1544.      * List test suites within a test plan alphabetically
  1545.      * 
  1546.      * @param struct $args
  1547.      * @param string $args["devKey"]
  1548.      * @param int $args["testplanid"]
  1549.      * @return mixed $resultInfo
  1550.      */
  1551.      public function getTestSuitesForTestPlan($args)
  1552.      {
  1553.         $operation=__FUNCTION__;
  1554.          $msg_prefix="({$operation}) - ";
  1555.          $this->_setArgs($args);
  1556.  
  1557.         $checkFunctions = array('authenticate','checkTestPlanID');       
  1558.         $status_ok=$this->_runChecks($checkFunctions,$msg_prefix);       
  1559.         if($status_ok)
  1560.         {
  1561.             $testPlanID = $this->args[self::$testPlanIDParamName];            
  1562.             $result = $this->tplanMgr->get_testsuites($testPlanID);
  1563.             return     $result;
  1564.         }
  1565.         else
  1566.         {
  1567.             return $this->errors;
  1568.         } 
  1569.      }
  1570.     
  1571.     /**
  1572.      * create a test project
  1573.      * 
  1574.      * @param struct $args
  1575.      * @param string $args["devKey"]
  1576.      * @param string $args["testprojectname"]
  1577.      * @param string $args["testcaseprefix"]
  1578.      * @param string $args["notes"] OPTIONAL
  1579.      * @param map $args["options"] OPTIONAL ALL int treated as boolean
  1580.      *                keys  requirementsEnabled,testPriorityEnabled,automationEnabled,inventoryEnabled
  1581.      *
  1582.      * @param int $args["active"]  OPTIONAL
  1583.      * @param int $args["public"]  OPTIONAL
  1584.      *     
  1585.      * @return mixed $resultInfo
  1586.      */
  1587.     public function createTestProject($args)
  1588.     {
  1589.         $this->_setArgs($args);
  1590.         $msg_prefix="(" . __FUNCTION__ . ") - ";
  1591.         $checkRequestMethod='_check' . ucfirst(__FUNCTION__) . 'Request';
  1592.     
  1593.         if( $this->$checkRequestMethod($msg_prefix) && $this->userHasRight("mgt_modify_product"))
  1594.         {
  1595.             // function create($name,$color,$options,$notes,$active=1,$tcasePrefix='')
  1596.             
  1597.             // Now go for options (is any)
  1598.             // all enabled by DEFAULT
  1599.             $options = new stdClass();
  1600.             $options->requirementsEnabled = 1;
  1601.             $options->testPriorityEnabled = 1;
  1602.             $options->automationEnabled = 1;
  1603.             $options->inventoryEnabled = 1;
  1604.  
  1605.             if( $this->_isParamPresent(self::$optionsParamName,$messagePrefix) )
  1606.             {
  1607.                 // has to be an array ?
  1608.                 $dummy = $this->args[self::$optionsParamName];
  1609.                 if( is_array($dummy) )
  1610.                 {
  1611.                     foreach($dummy as $key => $value)
  1612.                     {
  1613.                         $options->$key = $value > 0 ? 1 : 0;
  1614.                     }
  1615.                 }
  1616.             }
  1617.  
  1618.             // other optional parameters (not of complex type)
  1619.             // key 2 check with default value is parameter is missing
  1620.             $keys2check = array(self::$activeParamName => 1,self::$publicParamName => 1,
  1621.                                 self::$noteParamName => '');
  1622.               foreach($keys2check as $key => $value)
  1623.               {
  1624.                   $optional[$key]=$this->_isParamPresent($key) ? trim($this->args[$key]) : $value;
  1625.               }
  1626.  
  1627.             $name = htmlspecialchars($this->args[self::$testProjectNameParamName]);
  1628.             $prefix = htmlspecialchars($this->args[self::$testCasePrefixParamName]);
  1629.  
  1630.             $notes = htmlspecialchars($optional[self::$noteParamName]);
  1631.             $active = $optional[self::$activeParamName];
  1632.             $public = $optional[self::$publicParamName];
  1633.       
  1634.             $active = $active > 0 ? 1 : 0;
  1635.               $public = $public > 0 ? 1 : 0;
  1636.       
  1637.             $info=$this->tprojectMgr->create($name,'',$options,$notes,$active,$prefix,$public);
  1638.             $resultInfo = array();
  1639.             $resultInfo[]array("operation" => __FUNCTION__,
  1640.                                 "additionalInfo" => null,
  1641.                                 "status" => true, "id" => $info, "message" => <a href="../TestlinkAPI/_APIErrors.php.html#defineGENERAL_SUCCESS_STR">GENERAL_SUCCESS_STR</a>);
  1642.             return $resultInfo;
  1643.         }
  1644.         else
  1645.         {
  1646.             return $this->errors;
  1647.         }    
  1648.       
  1649.     }
  1650.     
  1651.   /**
  1652.    * _checkCreateTestProjectRequest
  1653.    *
  1654.    */
  1655.   protected function _checkCreateTestProjectRequest($msg_prefix)
  1656.     {
  1657.       $status_ok=$this->authenticate();
  1658.       $name=$this->args[self::$testProjectNameParamName];
  1659.       $prefix=$this->args[self::$testCasePrefixParamName];
  1660.       
  1661.       if( $status_ok )
  1662.       {
  1663.           $check_op=$this->tprojectMgr->checkNameSintax($name);
  1664.           $status_ok=$check_op['status_ok'];     
  1665.           if(!$status_ok)
  1666.           {     
  1667.                $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineTESTPROJECTNAME_SINTAX_ERROR">TESTPROJECTNAME_SINTAX_ERROR</a>, 
  1668.                                                $msg_prefix . $check_op['msg']);
  1669.           }
  1670.       }
  1671.       
  1672.       if( $status_ok ) 
  1673.       {
  1674.           $check_op=$this->tprojectMgr->checkNameExistence($name);
  1675.           $status_ok=$check_op['status_ok'];     
  1676.           if(!$status_ok)
  1677.           {     
  1678.                $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineTESTPROJECTNAME_EXISTS">TESTPROJECTNAME_EXISTS</a>, 
  1679.                                                $msg_prefix . $check_op['msg']);
  1680.           }
  1681.       }
  1682.  
  1683.       if( $status_ok ) 
  1684.       {
  1685.           $status_ok=!empty($prefix);
  1686.           if(!$status_ok)
  1687.           {     
  1688.                $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineTESTPROJECT_TESTCASEPREFIX_IS_EMPTY">TESTPROJECT_TESTCASEPREFIX_IS_EMPTY</a>, 
  1689.                                                $msg_prefix . $check_op['msg']);
  1690.           }
  1691.       }
  1692.  
  1693.       if( $status_ok ) 
  1694.       {
  1695.            $info=$this->tprojectMgr->get_by_prefix($prefix);
  1696.            if( !($status_ok = is_null($info)) )
  1697.            {
  1698.               $msg = $msg_prefix . sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#defineTPROJECT_PREFIX_ALREADY_EXISTS_STR">TPROJECT_PREFIX_ALREADY_EXISTS_STR</a>,$prefix,$info['name']);
  1699.               $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineTPROJECT_PREFIX_ALREADY_EXISTS">TPROJECT_PREFIX_ALREADY_EXISTS</a>,$msg);
  1700.            }
  1701.       }
  1702.  
  1703.         return $status_ok;
  1704.     }
  1705.  
  1706.     
  1707.     
  1708.     /**
  1709.      * List test cases within a test suite
  1710.      * 
  1711.      * By default test cases that are contained within child suites 
  1712.      * will be returned. 
  1713.      * Set the deep flag to false if you only want test cases in the test suite provided 
  1714.      * and no child test cases.
  1715.      *  
  1716.      * @param struct $args
  1717.      * @param string $args["devKey"]
  1718.      * @param int $args["testsuiteid"]
  1719.      * @param boolean $args["deep"] - optional (default is true)
  1720.      * @param boolean $args["details"] - optional (default is simple)
  1721.      *                                use full if you want to get 
  1722.      *                                summary,steps & expected_results
  1723.      *
  1724.      * @return mixed $resultInfo
  1725.      *
  1726.      *
  1727.      */
  1728.      public function getTestCasesForTestSuite($args)
  1729.      {
  1730.         $operation=__FUNCTION__;
  1731.          $msg_prefix="({$operation}) - ";
  1732.         
  1733.         $this->_setArgs($args);
  1734.         $status_ok=$this->_runChecks(array('authenticate','checkTestSuiteID'),$msg_prefix);       
  1735.         
  1736.         $details='simple';
  1737.         $key2search=self::$detailsParamName;
  1738.         if( $this->_isParamPresent($key2search) )
  1739.         {
  1740.             $details=$this->args[$key2search];  
  1741.         }
  1742.             
  1743.         if($status_ok && $this->userHasRight("mgt_view_tc"))
  1744.         {        
  1745.             $testSuiteID = $this->args[self::$testSuiteIDParamName];
  1746.             $tsuiteMgr = new testsuite($this->dbObj);
  1747.  
  1748.             // BUGID 2179
  1749.             if(!$this->_isDeepPresent() || $this->args[self::$deepParamName] )
  1750.             {
  1751.                 $pfn = 'get_testcases_deep';
  1752.             }    
  1753.             else
  1754.             {
  1755.                 $pfn = 'get_children_testcases';
  1756.             }
  1757.             return $tsuiteMgr->$pfn($testSuiteID,$details);
  1758.             
  1759.             
  1760.         }
  1761.         else
  1762.         {
  1763.             return $this->errors;
  1764.         }
  1765.      }
  1766.  
  1767.   /**
  1768.   * Find a test case by its name
  1769.   * 
  1770.   * <b>Searching is case sensitive.</b> The test case will only be returned if there is a definite match.
  1771.   * If possible also pass the string for the test suite name. 
  1772.   *
  1773.   * No results will be returned if there are test cases with the same name that match the criteria provided.  
  1774.   * 
  1775.   * @param struct $args
  1776.   * @param string $args["devKey"]
  1777.   * @param string $args["testcasename"]
  1778.   * @param string $args["testsuitename"] - optional
  1779.   * @param string $args["testprojectname"] - optional
  1780.   * @param string $args["testcasepathname"] - optional
  1781.   *               Full test case path name, starts with test project name
  1782.   *               pieces separator -> :: -> default value of getByPathName()
  1783.   * @return mixed $resultInfo
  1784.   */
  1785.   public function getTestCaseIDByName($args)
  1786.   {
  1787.         $msg_prefix="(" .__FUNCTION__ . ") - ";
  1788.         $status_ok=true;
  1789.           $this->_setArgs($args);
  1790.         $result = null;
  1791.       
  1792.           $checkFunctions = array('authenticate','checkTestCaseName');       
  1793.           $status_ok=$this->_runChecks($checkFunctions,$msg_prefix) && $this->userHasRight("mgt_view_tc");       
  1794.       
  1795.           if( $status_ok )
  1796.           {            
  1797.               $testCaseName = $this->args[self::$testCaseNameParamName];
  1798.               $testCaseMgr = new testcase($this->dbObj);
  1799.  
  1800.               $keys2check = array(self::$testSuiteNameParamName,self::$testCasePathNameParamName,
  1801.                                   self::$testProjectNameParamName);
  1802.             foreach($keys2check as $key)
  1803.               {
  1804.                   $optional[$key]=$this->_isParamPresent($key) ? trim($this->args[$key]) : '';
  1805.               }
  1806.   
  1807.             // 20091128 - franciscom
  1808.             if( $optional[self::$testCasePathNameParamName] != '' )
  1809.             {
  1810.                   $dummy = $testCaseMgr->getByPathName($optional[self::$testCasePathNameParamName]);
  1811.                   if( !is_null($dummy) )
  1812.                   {
  1813.                       $result[0] = $dummy;
  1814.                   }
  1815.             }
  1816.             else
  1817.             {
  1818.                   $result = $testCaseMgr->get_by_name($testCaseName,$optional[self::$testSuiteNameParamName],
  1819.                                                     $optional[self::$testProjectNameParamName]);
  1820.               }
  1821.               if(0 == sizeof($result))
  1822.               {
  1823.                   $status_ok=false;
  1824.                   $this->errors[] = new IXR_ERROR(<a href="../TestlinkAPI/_APIErrors.php.html#defineNO_TESTCASE_BY_THIS_NAME">NO_TESTCASE_BY_THIS_NAME</a>, 
  1825.                                                   $msg_prefix . <a href="../TestlinkAPI/_APIErrors.php.html#defineNO_TESTCASE_BY_THIS_NAME_STR">NO_TESTCASE_BY_THIS_NAME_STR</a>);
  1826.                   return $this->errors;
  1827.               }
  1828.       }
  1829.       return $status_ok ? $result : $this->errors; 
  1830.   }
  1831.      
  1832.      /**
  1833.       * createTestCase
  1834.         * @param struct $args
  1835.         * @param string $args["devKey"]
  1836.         * @param string $args["testcasename"]
  1837.         * @param int    $args["testsuiteid"]: test case parent test suite id
  1838.         * @param int    $args["testprojectid"]: test case parent test suite id
  1839.         *
  1840.         * @param string $args["authorlogin"]: to set test case author
  1841.         * @param string $args["summary"]
  1842.         * @param string $args["steps"]
  1843.         *
  1844.         * @param string $args["preconditions"] - optional
  1845.       * @param string $args["importance"] - optional - see const.inc.php for domain
  1846.       * @param string $args["execution"] - optional - see ... for domain
  1847.       * @param string $args["order'] - optional
  1848.       * @param string $args["internalid"] - optional - do not use
  1849.       * @param string $args["checkduplicatedname"] - optional
  1850.       * @param string $args["actiononduplicatedname"] - optional
  1851.       *
  1852.         * @return mixed $resultInfo
  1853.       * @return string $resultInfo['operation'] - verbose operation
  1854.       * @return boolean $resultInfo['status'] - verbose operation
  1855.       * @return int $resultInfo['id'] - test case internal ID (Database ID)
  1856.       * @return mixed $resultInfo['additionalInfo'] 
  1857.       * @return int $resultInfo['additionalInfo']['id'] same as $resultInfo['id']
  1858.       * @return int $resultInfo['additionalInfo']['external_id'] without prefix
  1859.       * @return int $resultInfo['additionalInfo']['status_ok'] 1/0
  1860.       * @return string $resultInfo['additionalInfo']['msg'] - for debug 
  1861.       * @return string $resultInfo['additionalInfo']['new_name'] only present if new name generation was needed
  1862.       * @return int $resultInfo['additionalInfo']['version_number']
  1863.       * @return boolean $resultInfo['additionalInfo']['has_duplicate'] - for debug 
  1864.       * @return string $resultInfo['message'] operation message
  1865.       */
  1866.      public function createTestCase($args)
  1867.      {
  1868.         $operation=__FUNCTION__;
  1869.          $msg_prefix="({$operation}) - ";
  1870.         
  1871.         $keywordSet='';
  1872.         $this->_setArgs($args);
  1873.         $checkFunctions = array('authenticate','checkTestProjectID','checkTestSuiteID','checkTestCaseName');
  1874.         $status_ok=$this->_runChecks($checkFunctions,$msg_prefix) && $this->userHasRight("mgt_modify_tc");
  1875.  
  1876.         if( $status_ok )
  1877.         {
  1878.               $keys2check = array(self::$authorLoginParamName,self::$summaryParamName, self::$stepsParamName);
  1879.               foreach($keys2check as $key)
  1880.               {
  1881.                   if(!$this->_isParamPresent($key))
  1882.                   {
  1883.                       $status_ok = false;
  1884.                       $msg = $msg_prefix . sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#defineMISSING_REQUIRED_PARAMETER_STR">MISSING_REQUIRED_PARAMETER_STR</a>,$key);
  1885.                       $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineMISSING_REQUIRED_PARAMETER">MISSING_REQUIRED_PARAMETER</a>, $msg);                      
  1886.                   }   
  1887.               }
  1888.         }                        
  1889.  
  1890.         if( $status_ok )
  1891.         {
  1892.             $author_id = tlUser::doesUserExist($this->dbObj,$this->args[self::$authorLoginParamName]);                
  1893.             if( !($status_ok = !is_null($author_id)) )
  1894.             {
  1895.                 $msg = $msg_prefix . sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#defineNO_USER_BY_THIS_LOGIN_STR">NO_USER_BY_THIS_LOGIN_STR</a>,$this->args[self::$authorLoginParamName]);
  1896.                  $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineNO_USER_BY_THIS_LOGIN">NO_USER_BY_THIS_LOGIN</a>, $msg);                
  1897.              }
  1898.         }
  1899.  
  1900.         if( $status_ok )
  1901.         {
  1902.             $keywordSet=$this->getKeywordSet($this->args[self::$testProjectIDParamName]);
  1903.         }
  1904.  
  1905.         if( $status_ok )
  1906.         {
  1907.             // Optional parameters
  1908.             $opt=array(self::$importanceParamName => 2,
  1909.                        self::$executionTypeParamName => TESTCASE_EXECUTION_TYPE_MANUAL,
  1910.                        self::$orderParamName => testcase::DEFAULT_ORDER,
  1911.                        self::$internalIDParamName => testcase::AUTOMATIC_ID,
  1912.                        self::$checkDuplicatedNameParamName => testcase::DONT_CHECK_DUPLICATE_NAME,
  1913.                        self::$actionOnDuplicatedNameParamName => 'generate_new',
  1914.                        self::$preconditionsParamName => '');
  1915.         
  1916.                 foreach($opt as $key => $value)
  1917.                 {
  1918.                     if($this->_isParamPresent($key))
  1919.                     {
  1920.                         $opt[$key]=$this->args[$key];      
  1921.                     }   
  1922.                 }
  1923.         }
  1924.         
  1925.              
  1926.         if( $status_ok )
  1927.         {
  1928.             $options = array( 'check_duplicate_name' => $opt[self::$checkDuplicatedNameParamName],
  1929.                               'action_on_duplicate_name' => $opt[self::$actionOnDuplicatedNameParamName]);
  1930.    
  1931.             $op_result=$this->tcaseMgr->create($this->args[self::$testSuiteIDParamName],
  1932.                                                $this->args[self::$testCaseNameParamName],
  1933.                                                $this->args[self::$summaryParamName],
  1934.                                                $opt[self::$preconditionsParamName],
  1935.                                                $this->args[self::$stepsParamName],
  1936.                                                $author_id,$keywordSet,
  1937.                                                $opt[self::$orderParamName],
  1938.                                                $opt[self::$internalIDParamName],
  1939.                                                $opt[self::$executionTypeParamName],
  1940.                                                $opt[self::$importanceParamName],
  1941.                                                $options);
  1942.             
  1943.             $resultInfo=array();
  1944.                $resultInfo[] = array("operation" => $operation, "status" => true, 
  1945.                                   "id" => $op_result['id'], 
  1946.                                   "additionalInfo" => $op_result,
  1947.                                   "message" => <a href="../TestlinkAPI/_APIErrors.php.html#defineGENERAL_SUCCESS_STR">GENERAL_SUCCESS_STR</a>);
  1948.         } 
  1949.         return ($status_ok ? $resultInfo : $this->errors);
  1950.      }    
  1951.      
  1952.      /**
  1953.       * Update an existing test case
  1954.       */
  1955.      public function updateTestCase($args)
  1956.      {
  1957.          // TODO: Implement
  1958.      }          
  1959.  
  1960.  
  1961.  
  1962.      /**
  1963.      * Reports a result for a single test case
  1964.      *
  1965.      * @param struct $args
  1966.      * @param string $args["devKey"]
  1967.      * @param int $args["testcaseid"]: optional, if not present           
  1968.      *                                 testcaseexternalid must be present
  1969.      *
  1970.      * @param int $args["testcaseexternalid"]: optional, if does not is present           
  1971.      *                                         testcaseid must be present
  1972.      *
  1973.      *
  1974.      *
  1975.      * @param int $args["testplanid"] 
  1976.      * @param string $args["status"] - status is {@link $validStatusList}
  1977.      * @param int $args["buildid"] - optional.
  1978.      *                               if not present and $args["buildname"] exists
  1979.      *                                 then 
  1980.      *                                    $args["buildname"] will be checked and used if valid
  1981.      *                               else 
  1982.      *                                    build with HIGHEST ID will be used
  1983.      *
  1984.      * @param int $args["buildname"] - optional.
  1985.      *                               if not present Build with higher internal ID will be used
  1986.      *
  1987.      *
  1988.      * @param string $args["notes"] - optional
  1989.      * @param bool $args["guess"] - optional defining whether to guess optinal params or require them 
  1990.      *                                               explicitly default is true (guess by default)
  1991.      *
  1992.      * @param string $args["bugid"] - optional
  1993.      *
  1994.      * @param string $args["platformid"] - optional, if not present platformname must be present
  1995.      * @param string $args["platformname"] - optional, if not present platformid must be present
  1996.      *    
  1997.      *
  1998.      * @param string $args["customfields"] - optional
  1999.      *               contains an map with key:Custom Field Name, value: value for CF.
  2000.      *               VERY IMPORTANT: value must be formatted in the way it's written to db,
  2001.      *               this is important for types like:
  2002.      *
  2003.      *               DATE: strtotime()
  2004.      *               DATETIME: mktime()
  2005.      *               MULTISELECTION LIST / CHECKBOX / RADIO: se multipli selezione ! come separatore
  2006.      *
  2007.      *
  2008.      *               these custom fields must be configured to be writte during execution.
  2009.      *               If custom field do not meet condition value will not be written
  2010.      *
  2011.      * @param boolean $args["overwrite"] - optional, if present and true, then last execution
  2012.      *                for (testcase,testplan,build,platform) will be overwritten.            
  2013.      *
  2014.      * @return mixed $resultInfo 
  2015.      *                 [status]    => true/false of success
  2016.      *                 [id]          => result id or error code
  2017.      *                 [message]    => optional message for error message string
  2018.      * @access public
  2019.      *
  2020.      * @internal revisions
  2021.      * 20101208 - franciscom - BUGID 4082 - no check on overwrite value
  2022.      *
  2023.      */
  2024.     public function reportTCResult($args)
  2025.     {        
  2026.         $resultInfo = array();
  2027.         $operation=__FUNCTION__;
  2028.         $msg_prefix="({$operation}) - ";
  2029.  
  2030.         $this->_setArgs($args);              
  2031.         $resultInfo[0]["status"] = true;
  2032.         
  2033.         $checkFunctions = array('authenticate','checkTestCaseIdentity','checkTestPlanID',
  2034.                                 'checkBuildID','checkStatus');
  2035.                                 
  2036.         $status_ok=$this->_runChecks($checkFunctions,$msg_prefix);       
  2037.  
  2038.            if($status_ok)
  2039.         {            
  2040.             // This check is needed only if test plan has platforms
  2041.             $platformSet = $this->tplanMgr->getPlatforms($this->args[self::$testPlanIDParamName],
  2042.                                                           array('outputFormat' => 'map'));  
  2043.             $targetPlatform = null;
  2044.             if( !is_null($platformSet) )
  2045.             {       
  2046.                 $status_ok = $this->checkPlatformIdentity($this->args[self::$testPlanIDParamName],$platformSet,$msg_prefix);
  2047.                 if($status_ok)
  2048.                 {
  2049.                     $targetPlatform[$this->args[self::$platformIDParamName]] = $platformSet[$this->args[self::$platformIDParamName]];
  2050.                 }
  2051.             }
  2052.             
  2053.             $status_ok = $status_ok && $this->_checkTCIDAndTPIDValid($targetPlatform,$msg_prefix);
  2054.         }
  2055.     
  2056.         if($status_ok && $this->userHasRight("testplan_execute"))
  2057.         {        
  2058.             $executionID = 0;    
  2059.             $resultInfo[0]["operation"] = $operation;
  2060.             $resultInfo[0]["overwrite"] = false;
  2061.             $resultInfo[0]["status"] = true;
  2062.             $resultInfo[0]["message"] = <a href="../TestlinkAPI/_APIErrors.php.html#defineGENERAL_SUCCESS_STR">GENERAL_SUCCESS_STR</a>;
  2063.  
  2064.             // BUGID 4082 - no check on overwrite value
  2065.             if($this->_isParamPresent(self::$overwriteParamName) && $this->args[self::$overwriteParamName])
  2066.             {
  2067.                     $executionID = $this->_updateResult();
  2068.                     $resultInfo[0]["overwrite"] = true;            
  2069.             }
  2070.             if($executionID == 0)
  2071.             {
  2072.                 $executionID = $this->_insertResultToDB();            
  2073.             } 
  2074.  
  2075.             $resultInfo[0]["id"] = $executionID;    
  2076.             
  2077.             // Do we need to insert a bug ?
  2078.             if($this->_isParamPresent(self::$bugIDParamName))
  2079.             {
  2080.                 $bugID = $this->args[self::$bugIDParamName];
  2081.                 $resultInfo[0]["bugidstatus"] = $this->_insertExecutionBug($executionID, $bugID);
  2082.             }
  2083.             
  2084.             
  2085.             if($this->_isParamPresent(self::$customFieldsParamName))
  2086.             {
  2087.                 $resultInfo[0]["customfieldstatus"] =  
  2088.                     $this->_insertCustomFieldExecValues($executionID);   
  2089.             }
  2090.             return $resultInfo;
  2091.         }
  2092.         else
  2093.         {
  2094.             return $this->errors;            
  2095.         }
  2096.  
  2097.     }
  2098.     
  2099.     
  2100.     /**
  2101.      * turn on/off testMode
  2102.      *
  2103.      * This method is meant primarily for testing and debugging during development
  2104.      * @param struct $args
  2105.      * @return boolean
  2106.      * @access protected
  2107.      */    
  2108.     public function setTestMode($args)
  2109.     {
  2110.         $this->_setArgs($args);
  2111.         
  2112.         if(!$this->_isTestModePresent())
  2113.         {
  2114.             $this->errors[] = new IXR_ERROR(<a href="../TestlinkAPI/_APIErrors.php.html#defineNO_TEST_MODE">NO_TEST_MODE</a>, <a href="../TestlinkAPI/_APIErrors.php.html#defineNO_TEST_MODE_STR">NO_TEST_MODE_STR</a>);
  2115.             return false;
  2116.         }
  2117.         else
  2118.         {
  2119.             // TODO: should probably validate that this is a bool or t/f string
  2120.             $this->testMode = $this->args[self::$testModeParamName];
  2121.             return true;            
  2122.         }
  2123.     }    
  2124.     
  2125.     
  2126.     /**
  2127.      * Helper method to see if the testcase identity provided is valid 
  2128.      * Identity can be specified in one of these modes:
  2129.      *
  2130.      * test case internal id
  2131.      * test case external id  (PREFIX-NNNN) 
  2132.      * 
  2133.      * This is the only method that should be called directly to check test case identoty
  2134.      *     
  2135.      * If everything OK, test case internal ID is setted.
  2136.      *
  2137.      * @param string $messagePrefix used to be prepended to error message
  2138.      *
  2139.      * @return boolean
  2140.      * @access protected
  2141.      */    
  2142.     protected function checkTestCaseIdentity($messagePrefix='')
  2143.     {
  2144.         // Three Cases - Internal ID, External ID, No Id        
  2145.         $status=true;
  2146.         $tcaseID=0;
  2147.         $my_errors=array();
  2148.         $fromExternal=false;
  2149.         $fromInternal=false;
  2150.  
  2151.         if($this->_isTestCaseIDPresent())
  2152.         {
  2153.               $fromInternal=true;
  2154.               $tcaseID = $this->args[self::$testCaseIDParamName];
  2155.               $status = true;
  2156.         }
  2157.         elseif ($this->_isTestCaseExternalIDPresent())
  2158.         {
  2159.             $fromExternal = true;
  2160.             $tcaseExternalID = $this->args[self::$testCaseExternalIDParamName]; 
  2161.             $tcaseCfg=config_get('testcase_cfg');
  2162.             $glueCharacter=$tcaseCfg->glue_character;
  2163.             $tcaseID=$this->tcaseMgr->getInternalID($tcaseExternalID,$glueCharacter);
  2164.             $status = $tcaseID > 0 ? true : false;
  2165.             
  2166.             //Invalid TestCase ID
  2167.             if( !$status )
  2168.             {
  2169.                   $my_errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineINVALID_TESTCASE_EXTERNAL_ID">INVALID_TESTCASE_EXTERNAL_ID</a>, 
  2170.                                              sprintf($messagePrefix . <a href="../TestlinkAPI/_APIErrors.php.html#defineINVALID_TESTCASE_EXTERNAL_ID_STR">INVALID_TESTCASE_EXTERNAL_ID_STR</a>,$tcaseExternalID));                  
  2171.             }
  2172.         }
  2173.         if( $status )
  2174.         {
  2175.             $my_errors=null;
  2176.             if($this->_isTestCaseIDValid($tcaseID,$messagePrefix))
  2177.             {
  2178.                 $this->_setTestCaseID($tcaseID);  
  2179.             }  
  2180.             else
  2181.             {  
  2182.                   if ($fromInternal)
  2183.                   {
  2184.                       $my_errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineINVALID_TCASEID">INVALID_TCASEID</a>, $messagePrefix . <a href="../TestlinkAPI/_APIErrors.php.html#defineINVALID_TCASEID_STR">INVALID_TCASEID_STR</a>);
  2185.                   } 
  2186.                   elseif ($fromExternal)
  2187.                   {
  2188.                       $my_errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineINVALID_TESTCASE_EXTERNAL_ID">INVALID_TESTCASE_EXTERNAL_ID</a>, 
  2189.                                                  sprintf($messagePrefix . <a href="../TestlinkAPI/_APIErrors.php.html#defineINVALID_TESTCASE_EXTERNAL_ID_STR">INVALID_TESTCASE_EXTERNAL_ID_STR</a>,$tcaseExternalID));
  2190.                   }
  2191.                   $status=false;
  2192.             }        
  2193.         }
  2194.         
  2195.         
  2196.         if (!$status)
  2197.         {
  2198.             foreach($my_errors as $error_msg)
  2199.             {
  2200.                   $this->errors[] = $error_msg; 
  2201.             } 
  2202.         }
  2203.         return $status;
  2204.     }   
  2205.  
  2206.      /**
  2207.      * getTestCasesForTestPlan
  2208.      * List test cases linked to a test plan
  2209.      * 
  2210.      * @param struct $args
  2211.      * @param string $args["devKey"]
  2212.      * @param int $args["testplanid"]
  2213.      * @param int $args["testcaseid"] - optional
  2214.      * @param int $args["buildid"] - optional
  2215.      * @param int $args["keywordid"] - optional mutual exclusive with $args["keywords"]
  2216.      * @param int $args["keywords"] - optional  mutual exclusive with $args["keywordid"]
  2217.      *
  2218.      * @param boolean $args["executed"] - optional
  2219.      * @param int $args["$assignedto"] - optional
  2220.      * @param string $args["executestatus"] - optional
  2221.      * @param array $args["executiontype"] - optional
  2222.      * @param array $args["getstepinfo"] - optional - default false
  2223.      *
  2224.      * @return mixed $resultInfo
  2225.      */
  2226.      public function getTestCasesForTestPlan($args)
  2227.      {
  2228.  
  2229.         $operation=__FUNCTION__;
  2230.          $msg_prefix="({$operation}) - ";
  2231.          
  2232.         // Optional parameters that are not mutual exclusive
  2233.         $opt=array(self::$testCaseIDParamName => null,
  2234.                    self::$buildIDParamName => null,
  2235.                    self::$keywordIDParamName => null,
  2236.                    self::$executedParamName => null,
  2237.                    self::$assignedToParamName => null,
  2238.                    self::$executeStatusParamName => null,
  2239.                    self::$executionTypeParamName => null,
  2240.                    self::$getStepsInfoParamName => false);
  2241.              
  2242.         $optMutualExclusive=array(self::$keywordIDParamName => null,
  2243.                                   self::$keywordNameParamName => null);     
  2244.         $this->_setArgs($args);
  2245.         
  2246.         // Test Case ID, Build ID are checked if present
  2247.         if(!$this->_checkGetTestCasesForTestPlanRequest($msg_prefix) && $this->userHasRight("mgt_view_tc"))
  2248.         {
  2249.             return $this->errors;
  2250.         }
  2251.         
  2252.         $tplanid = $this->args[self::$testPlanIDParamName];
  2253.         $tplanInfo = $this->tplanMgr->tree_manager->get_node_hierarchy_info($tplanid);
  2254.         
  2255.         foreach($opt as $key => $value)
  2256.         {
  2257.             if($this->_isParamPresent($key))
  2258.             {
  2259.                 $opt[$key]=$this->args[$key];      
  2260.             }   
  2261.         }
  2262.         
  2263.         // 20101110 - franciscom
  2264.         // honors what has been written in documentation
  2265.         $keywordSet = $opt[self::$keywordIDParamName];
  2266.         if( is_null($keywordSet) )
  2267.         {
  2268.             $keywordSet = null;
  2269.             $keywordList = $this->getKeywordSet($tplanInfo['parent_id']);
  2270.             if( !is_null($keywordList) )
  2271.             {
  2272.                 $keywordSet = explode(",",$keywordList);
  2273.             }
  2274.         }
  2275.         // BUGID 4041
  2276.         // BUGID 3604
  2277.         $options = array('executed_only' => $opt[self::$executedParamName], 
  2278.                          'steps_info' => $opt[self::$getStepsInfoParamName],
  2279.                          'details' => 'full','output' => 'mapOfMap' );
  2280.             
  2281.         // BUGID 3992                 
  2282.         $filters = array('tcase_id' => $opt[self::$testCaseIDParamName],
  2283.                          'keyword_id' => $keywordSet,
  2284.                          'assigned_to' => $opt[self::$assignedToParamName],
  2285.                          'exec_status' => $opt[self::$executeStatusParamName],
  2286.                          'build_id' => $opt[self::$buildIDParamName],
  2287.                          'exec_type' => $opt[self::$executionTypeParamName]);
  2288.         
  2289.         
  2290.         $recordset=$this->tplanMgr->get_linked_tcversions($tplanid,$filters,$options);
  2291.         return $recordset;
  2292.      }
  2293.  
  2294.  
  2295.     /**
  2296.      * Run all the necessary checks to see if a GetTestCasesForTestPlanRequest()
  2297.      * can be accepted.
  2298.      *
  2299.      * @param string $messagePrefix used to be prepended to error message
  2300.      *
  2301.      * @return boolean
  2302.      * @access protected
  2303.      */
  2304.     protected function _checkGetTestCasesForTestPlanRequest($messagePrefix='')
  2305.     {
  2306.         $status=$this->authenticate();
  2307.         if($status)
  2308.         {
  2309.             $status &=$this->checkTestPlanID($messagePrefix);
  2310.             
  2311.             if($status && $this->_isTestCaseIDPresent($messagePrefix))
  2312.             {
  2313.                 $status &=$this->_checkTCIDAndTPIDValid(null,$messagePrefix);
  2314.             }
  2315.             if($status && $this->_isBuildIDPresent($messagePrefix))  
  2316.             {
  2317.                 $status &=$this->checkBuildID($messagePrefix);
  2318.             }
  2319.         }
  2320.         return $status;
  2321.     }
  2322.     
  2323.   /**
  2324.      * Gets value of a Custom Field with scope='design' for a given Test case
  2325.      *
  2326.      * @param struct $args
  2327.      * @param string $args["devKey"]: used to check if operation can be done.
  2328.      *                                if devKey is not valid => abort.
  2329.      *
  2330.      * @param string $args["testcaseexternalid"]:  
  2331.      * @param string $args["version"]: version number  
  2332.      * @param string $args["testprojectid"]: 
  2333.      * @param string $args["customfieldname"]: custom field name
  2334.      * @param string $args["details"] optional, changes output information
  2335.      *                                null or 'value' => just value
  2336.      *                                'full' => a map with all custom field definition
  2337.      *                                             plus value and internal test case id
  2338.      *                                'simple' => value plus custom field name, label, and type (as code).
  2339.      *
  2340.      * @return mixed $resultInfo
  2341.      *                 
  2342.      * @access public
  2343.      */        
  2344.     public function getTestCaseCustomFieldDesignValue($args)
  2345.     {
  2346.         $msg_prefix="(" .__FUNCTION__ . ") - ";
  2347.         $this->_setArgs($args);    
  2348.         
  2349.         // 20101020 - franciscom - added checkTestCaseVersionNumber    
  2350.         $checkFunctions = array('authenticate','checkTestProjectID','checkTestCaseIdentity',
  2351.                                 'checkTestCaseVersionNumber');
  2352.         $status_ok=$this->_runChecks($checkFunctions,$msg_prefix);       
  2353.  
  2354.         if( $status_ok )
  2355.         {
  2356.             $status_ok=$this->_isParamPresent(self::$customFieldNameParamName,$msg_prefix,self::SET_ERROR);
  2357.         }
  2358.         
  2359.         
  2360.         if($status_ok)
  2361.         {
  2362.             $ret = $this->checkTestCaseAncestry();
  2363.             $status_ok = $ret['status_ok'];
  2364.             if( $status_ok )
  2365.             {
  2366.                 // Check if version number exists for Test Case
  2367.                 $ret = $this->checkTestCaseVersionNumberAncestry();
  2368.                 $status_ok = $ret['status_ok'];
  2369.             }
  2370.             
  2371.             if($status_ok )
  2372.             {
  2373.                 $status_ok=$this->_checkGetTestCaseCustomFieldDesignValueRequest($msg_prefix);
  2374.             }
  2375.             else 
  2376.             {
  2377.                 $this->errors[] = new IXR_Error($ret['error_code'], $msg_prefix . $ret['error_msg']); 
  2378.             }           
  2379.         }
  2380.         
  2381.         if($status_ok && $this->userHasRight("mgt_view_tc"))
  2382.         {
  2383.             $details='value';
  2384.             if( $this->_isParamPresent(self::$detailsParamName) )
  2385.             {
  2386.                 $details=$this->args[self::$detailsParamName];  
  2387.             }
  2388.         
  2389.             
  2390.             $cf_name=$this->args[self::$customFieldNameParamName];
  2391.             $tproject_id=$this->args[self::$testProjectIDParamName];
  2392.             $tcase_id=$this->args[self::$testCaseIDParamName];
  2393.             
  2394.             $cfield_mgr = $this->tprojectMgr->cfield_mgr;
  2395.             $cfinfo = $cfield_mgr->get_by_name($cf_name);
  2396.             $cfield = current($cfinfo);
  2397.             $filters = array('cfield_id' => $cfield['id']);
  2398.             $cfieldSpec = $this->tcaseMgr->get_linked_cfields_at_design($tcase_id,$this->tcVersionID,null,$filters,$tproject_id);
  2399.             
  2400.             switch($details)
  2401.             {
  2402.                 case 'full':
  2403.                     $retval = $cfieldSpec[$cfield['id']]; 
  2404.                 break;
  2405.                 
  2406.                 case 'simple':
  2407.                     $retval = array('name' => $cf_name, 'label' => $cfieldSpec[$cfield['id']]['label'], 
  2408.                                     'type' => $cfieldSpec[$cfield['id']]['type'], 
  2409.                                     'value' => $cfieldSpec[$cfield['id']]['value']);
  2410.                 break;
  2411.                 
  2412.                 case 'value':
  2413.                 default:
  2414.                     $retval=$cfieldSpec[$cfield['id']]['value'];
  2415.                 break;
  2416.                 
  2417.             }
  2418.             return $retval;
  2419.         }
  2420.         else
  2421.         {
  2422.             return $this->errors;
  2423.         } 
  2424.   }
  2425.   
  2426.       /**
  2427.      * Run all the necessary checks to see if GetTestCaseCustomFieldDesignValueRequest()
  2428.      * can be accepted.
  2429.      *  
  2430.      * - Custom Field exists ?
  2431.      * - Can be used on a test case ?
  2432.      * - Custom Field scope includes 'design' ?
  2433.      * - is linked to testproject that owns test case ?
  2434.      *
  2435.      * @param string $messagePrefix used to be prepended to error message
  2436.      *
  2437.      * @return boolean
  2438.      * @access protected
  2439.      */
  2440.     protected function _checkGetTestCaseCustomFieldDesignValueRequest($messagePrefix='')
  2441.     {        
  2442.         // $status_ok=$this->authenticate($messagePrefix);
  2443.         $cf_name=$this->args[self::$customFieldNameParamName];
  2444.  
  2445.           //  $testCaseIDParamName = "testcaseid";
  2446.         //  public static $testCaseExternalIDParamName = "testcaseexternalid";
  2447.   
  2448.         // Custom Field checks:
  2449.         // - Custom Field exists ?
  2450.         // - Can be used on a test case ?
  2451.         // - Custom Field scope includes 'design' ?
  2452.         // - is linked to testproject that owns test case ?
  2453.         //
  2454.  
  2455.         // - Custom Field exists ?
  2456.         $cfield_mgr=$this->tprojectMgr->cfield_mgr; 
  2457.         $cfinfo=$cfield_mgr->get_by_name($cf_name);
  2458.         if( !($status_ok=!is_null($cfinfo)) )
  2459.         {
  2460.              $msg = sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#defineNO_CUSTOMFIELD_BY_THIS_NAME_STR">NO_CUSTOMFIELD_BY_THIS_NAME_STR</a>,$cf_name);
  2461.              $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineNO_CUSTOMFIELD_BY_THIS_NAME">NO_CUSTOMFIELD_BY_THIS_NAME</a>, $messagePrefix . $msg);
  2462.         }
  2463.       
  2464.         // - Can be used on a test case ?
  2465.         if( $status_ok )
  2466.         {
  2467.             $cfield=current($cfinfo);
  2468.             $status_ok = (strcasecmp($cfield['node_type'],'testcase') == 0 );
  2469.             if( !$status_ok )
  2470.             {
  2471.                  $msg = sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#defineCUSTOMFIELD_NOT_APP_FOR_NODE_TYPE_STR">CUSTOMFIELD_NOT_APP_FOR_NODE_TYPE_STR</a>,$cf_name,'testcase',$cfield['node_type']);
  2472.                  $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineCUSTOMFIELD_NOT_APP_FOR_NODE_TYPE">CUSTOMFIELD_NOT_APP_FOR_NODE_TYPE</a>, $messagePrefix . $msg);
  2473.             }
  2474.         }
  2475.  
  2476.         // - Custom Field scope includes 'design' ?
  2477.         if( $status_ok )
  2478.         {
  2479.             $status_ok = ($cfield['show_on_design'] || $cfield['enable_on_design']);
  2480.             if( !$status_ok )
  2481.             {
  2482.                  $msg = sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#defineCUSTOMFIELD_HAS_NOT_DESIGN_SCOPE_STR">CUSTOMFIELD_HAS_NOT_DESIGN_SCOPE_STR</a>,$cf_name);
  2483.                  $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineCUSTOMFIELD_HAS_NOT_DESIGN_SCOPE">CUSTOMFIELD_HAS_NOT_DESIGN_SCOPE</a>, $messagePrefix . $msg);
  2484.             }
  2485.         }
  2486.  
  2487.         // - is linked to testproject that owns test case ?
  2488.         if( $status_ok )
  2489.         {
  2490.             $allCF = $cfield_mgr->get_linked_to_testproject($this->args[self::$testProjectIDParamName]);
  2491.             $status_ok=!is_null($allCF) && isset($allCF[$cfield['id']]) ;
  2492.             if( !$status_ok )
  2493.             {
  2494.                 $tproject_info = $this->tprojectMgr->get_by_id($this->args[self::$testProjectIDParamName]);
  2495.                 $msg = sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#defineCUSTOMFIELD_NOT_ASSIGNED_TO_TESTPROJECT_STR">CUSTOMFIELD_NOT_ASSIGNED_TO_TESTPROJECT_STR</a>,
  2496.                                $cf_name,$tproject_info['name'],$this->args[self::$testProjectIDParamName]);
  2497.                 $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineCUSTOMFIELD_NOT_ASSIGNED_TO_TESTPROJECT">CUSTOMFIELD_NOT_ASSIGNED_TO_TESTPROJECT</a>, $messagePrefix . $msg);
  2498.             }
  2499.              
  2500.         }
  2501.       
  2502.         return $status_ok;
  2503.   }
  2504.  
  2505.  
  2506.  
  2507.       /**
  2508.      * getKeywordSet()
  2509.      *  
  2510.      * @param int tproject_id
  2511.      *            
  2512.      * @return string that represent a list of keyword id (comma is character separator)
  2513.      *
  2514.      * @access protected
  2515.      */
  2516.     protected function getKeywordSet($tproject_id)
  2517.     { 
  2518.         $kMethod=null;
  2519.         $keywordSet=null;
  2520.         if($this->_isParamPresent(self::$keywordNameParamName))
  2521.         {
  2522.             $kMethod='getValidKeywordSetByName';
  2523.             $accessKey=self::$keywordNameParamName;
  2524.         }
  2525.         else if ($this->_isParamPresent(self::$keywordIDParamName))
  2526.         {
  2527.             $kMethod='getValidKeywordSetById';
  2528.             $accessKey=self::$keywordIDParamName;
  2529.         }
  2530.         if( !is_null($kMethod) )
  2531.         {
  2532.             $keywordSet=$this->$kMethod($tproject_id,$this->args[$accessKey]);
  2533.         }
  2534.         
  2535.         return $keywordSet;
  2536.     }
  2537.     
  2538.  
  2539.  
  2540.       /**
  2541.      * getValidKeywordSetByName()
  2542.      *  
  2543.      * @param int $tproject_id
  2544.       * @param $keywords array of keywords names
  2545.      *
  2546.      * @return string that represent a list of keyword id (comma is character separator)
  2547.      *
  2548.      * @access protected
  2549.      */
  2550.     protected function getValidKeywordSetByName($tproject_id,$keywords)
  2551.     { 
  2552.         return $this->getValidKeywordSet($tproject_id,$keywords,true);
  2553.     }
  2554.     
  2555.      /**
  2556.       * 
  2557.       * @param $tproject_id the testprojectID the keywords belong
  2558.       * @param $keywords array of keywords or keywordIDs
  2559.       * @param $byName set this to true if $keywords is an array of keywords, false if it's an array of keywordIDs
  2560.       * @return string that represent a list of keyword id (comma is character separator)
  2561.       */
  2562.     protected function getValidKeywordSet($tproject_id,$keywords,$byName)
  2563.     {
  2564.         $keywordSet = '';
  2565.         $keywords = trim($keywords);
  2566.         if($keywords != "")
  2567.           {
  2568.             $a_keywords = explode(",",$keywords);
  2569.             $items_qty = count($a_keywords);
  2570.             for($idx = 0; $idx < $items_qty; $idx++)
  2571.             {
  2572.                 $a_keywords[$idx] = trim($a_keywords[$idx]);
  2573.             }
  2574.             $itemsSet = implode("','",$a_keywords);
  2575.             $sql = " SELECT keyword,id FROM {$this->tables['keywords'].
  2576.                    " WHERE testproject_id = {$tproject_id";
  2577.             
  2578.             if ($byName)
  2579.             {
  2580.                 $sql .= " AND keyword IN ('{$itemsSet}')";
  2581.             }
  2582.             else
  2583.             {
  2584.                 $sql .= " AND id IN ({$itemsSet})";
  2585.             }
  2586.              
  2587.             $keywordMap = $this->dbObj->fetchRowsIntoMap($sql,'keyword');
  2588.             if(!is_null($keywordMap))
  2589.             {
  2590.                 $a_items = null;
  2591.                 for($idx = 0; $idx < $items_qty; $idx++)
  2592.                 {
  2593.                     if(isset($keywordMap[$a_keywords[$idx]]))
  2594.                     {
  2595.                         $a_items[] = $keywordMap[$a_keywords[$idx]]['id'];  
  2596.                     }
  2597.                 }
  2598.                 if( !is_null($a_items))
  2599.                 {
  2600.                     $keywordSet = implode(",",$a_items);
  2601.                 }    
  2602.             }
  2603.         }  
  2604.         return $keywordSet;
  2605.      }
  2606.      
  2607.       /**
  2608.      * getValidKeywordSetById()
  2609.      *  
  2610.      * @param int $tproject_id
  2611.       * @param $keywords array of keywords ID
  2612.      *
  2613.      * @return string that represent a list of keyword id (comma is character separator)
  2614.      *
  2615.      * @access protected
  2616.      */
  2617.     protected function  getValidKeywordSetById($tproject_id,$keywords)
  2618.     {
  2619.         return $this->getValidKeywordSet($tproject_id,$keywords,false);
  2620.     }
  2621.  
  2622.  
  2623.       /**
  2624.      * checks if test case version number is a valid.
  2625.      * Checks is is positive intenger
  2626.      *  
  2627.      * @return boolean
  2628.      *
  2629.      * @access protected
  2630.      */
  2631.   protected function checkTestCaseVersionNumber()
  2632.   {
  2633.         $status=true;
  2634.         if(!($status=$this->_isParamPresent(self::$versionNumberParamName)))
  2635.         {
  2636.             $msg = sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#defineMISSING_REQUIRED_PARAMETER_STR">MISSING_REQUIRED_PARAMETER_STR</a>,self::$versionNumberParamName);
  2637.             $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineMISSING_REQUIRED_PARAMETER">MISSING_REQUIRED_PARAMETER</a>, $msg);                      
  2638.         }
  2639.         else
  2640.         {
  2641.             $version = $this->args[self::$versionNumberParamName];
  2642.             if( !($status = is_int($version)) )
  2643.             {
  2644.                 // BUGID 3456
  2645.                 $msg = sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#definePARAMETER_NOT_INT_STR">PARAMETER_NOT_INT_STR</a>,self::$versionNumberParamName,$version);
  2646.                 $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#definePARAMETER_NOT_INT">PARAMETER_NOT_INT</a>, $msg);
  2647.             }
  2648.             else 
  2649.             {
  2650.                 if( !($status = ($version > 0)) )
  2651.                 {
  2652.                     $msg = sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#defineVERSION_NOT_VALID_STR">VERSION_NOT_VALID_STR</a>,$version);
  2653.                     $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineVERSION_NOT_VALID">VERSION_NOT_VALID</a>,$msg);
  2654.                 }
  2655.             }
  2656.         }
  2657.         return $status;
  2658.   }
  2659.  
  2660.      /**
  2661.       * Add a test case version to a test plan 
  2662.       *
  2663.       * @param args['testprojectid']
  2664.       * @param args['testplanid']
  2665.       * @param args['testcaseexternalid']
  2666.       * @param args['version']
  2667.       * @param args['platformid'] - OPTIONAL Only if  test plan has no platforms
  2668.       * @param args['executionorder'] - OPTIONAL
  2669.       * @param args['urgency'] - OPTIONAL
  2670.       *
  2671.       */
  2672.     public function addTestCaseToTestPlan($args)
  2673.     {
  2674.         $operation=__FUNCTION__;
  2675.         $messagePrefix="({$operation}) - ";
  2676.         $this->_setArgs($args);
  2677.         
  2678.         $op_result=null;
  2679.         $additional_fields='';
  2680.         $doDeleteLinks = false;
  2681.         $doLink = false;
  2682.           $hasPlatforms = false;
  2683.         $hasPlatformIDArgs = false;
  2684.         $platform_id = 0;
  2685.         $checkFunctions = array('authenticate','checkTestProjectID','checkTestCaseVersionNumber',
  2686.                                 'checkTestCaseIdentity','checkTestPlanID');
  2687.         
  2688.         $status_ok=$this->_runChecks($checkFunctions,$messagePrefix) && $this->userHasRight("testplan_planning");       
  2689.         
  2690.         // Test Plan belongs to test project ?
  2691.         if( $status_ok )
  2692.         {
  2693.            $tproject_id = $this->args[self::$testProjectIDParamName];
  2694.            $tplan_id = $this->args[self::$testPlanIDParamName];
  2695.            $tplan_info = $this->tplanMgr->get_by_id($tplan_id);
  2696.            
  2697.            $sql=" SELECT id FROM {$this->tables['testplans']}.
  2698.                 " WHERE testproject_id={$tproject_id} AND id = {$tplan_id}";         
  2699.             
  2700.            $rs=$this->dbObj->get_recordset($sql);
  2701.         
  2702.            if( count($rs) != 1 )
  2703.            {
  2704.               $status_ok=false;
  2705.               $tproject_info = $this->tprojectMgr->get_by_id($tproject_id);
  2706.               $msg = sprintf(TPLAN_TPROJECT_KO_STR,$tplan_info['name'],$tplan_id,
  2707.                                                    $tproject_info['name'],$tproject_id);  
  2708.               $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineTPLAN_TPROJECT_KO">TPLAN_TPROJECT_KO</a>,$msg_prefix . $msg); 
  2709.            }
  2710.                       
  2711.         } 
  2712.        
  2713.         // Test Case belongs to test project ?
  2714.         if( $status_ok )
  2715.         {
  2716.             $ret = $this->checkTestCaseAncestry();
  2717.             if( !$ret['status_ok'] )
  2718.             {
  2719.                 $this->errors[] = new IXR_Error($ret['error_code'], $msg_prefix . $ret['error_msg']); 
  2720.             }           
  2721.         }
  2722.         
  2723.         // Does this Version number exist for this test case ?     
  2724.         if( $status_ok )
  2725.         {
  2726.             $tcase_id=$this->args[self::$testCaseIDParamName];
  2727.             $version_number=$this->args[self::$versionNumberParamName];
  2728.             $sql = " SELECT TCV.version,TCV.id " . 
  2729.                    " FROM {$this->tables['nodes_hierarchy']} NH, {$this->tables['tcversions']} TCV .
  2730.                    " WHERE NH.parent_id = {$tcase_id.
  2731.                    " AND TCV.version = {$version_number.
  2732.                    " AND TCV.id = NH.id ";
  2733.         
  2734.            $target_tcversion=$this->dbObj->fetchRowsIntoMap($sql,'version');
  2735.            if( !is_null($target_tcversion) && count($target_tcversion) != 1 )
  2736.            {
  2737.               $status_ok=false;
  2738.               $tcase_info=$this->tcaseMgr->get_by_id($tcase_id);
  2739.               $msg = sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#defineTCASE_VERSION_NUMBER_KO_STR">TCASE_VERSION_NUMBER_KO_STR</a>,$version_number,$tcase_external_id,$tcase_info[0]['name']);  
  2740.               $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineTCASE_VERSION_NUMBER_KO">TCASE_VERSION_NUMBER_KO</a>,$msg_prefix . $msg); 
  2741.            }                  
  2742.                    
  2743.         }     
  2744.  
  2745.         if( $status_ok )
  2746.         {
  2747.             // Optional parameters
  2748.             $additional_fields=null;
  2749.             $additional_values=null;
  2750.             $opt_fields=array(self::$urgencyParamName => 'urgency', self::$executionOrderParamName => 'node_order');
  2751.             $opt_values=array(self::$urgencyParamName => null, self::$executionOrderParamName => 1);
  2752.             foreach($opt_fields as $key => $field_name)
  2753.             {
  2754.                 if($this->_isParamPresent($key))
  2755.                 {
  2756.                         $additional_values[]=$this->args[$key];
  2757.                         $additional_fields[]=$field_name;              
  2758.                 }   
  2759.                 else
  2760.                 {
  2761.                     if( !is_null($opt_values[$key]) )
  2762.                      {
  2763.                         $additional_values[]=$opt_values[$key];
  2764.                         $additional_fields[]=$field_name;              
  2765.                     }
  2766.                  }
  2767.             }
  2768.         }
  2769.  
  2770.         if( $status_ok )
  2771.         {
  2772.             // 20100705 - work in progress - BUGID 3564
  2773.             // if test plan has platforms, platformid argument is MANDATORY
  2774.             $opt = array('outputFormat' => 'mapAccessByID');
  2775.             $platformSet = $this->tplanMgr->getPlatforms($tplan_id,$opt);  
  2776.               $hasPlatforms = !is_null($platformSet);
  2777.             $hasPlatformIDArgs = $this->_isParamPresent(self::$platformIDParamName);
  2778.             
  2779.             if( $hasPlatforms )
  2780.             {
  2781.                 if( $hasPlatformIDArgs )
  2782.                 {
  2783.                     // Check if platform id belongs to test plan
  2784.                     $platform_id = $this->args[self::$platformIDParamName];
  2785.                     $status_ok = isset($platformSet[$platform_id]);
  2786.                     if( !$status_ok )
  2787.                     {
  2788.                            $msg = sprintf( <a href="../TestlinkAPI/_APIErrors.php.html#definePLATFORM_ID_NOT_LINKED_TO_TESTPLAN_STR">PLATFORM_ID_NOT_LINKED_TO_TESTPLAN_STR</a>,
  2789.                                            $platform_id,$tplan_info['name']);
  2790.                            $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#definePLATFORM_ID_NOT_LINKED_TO_TESTPLAN">PLATFORM_ID_NOT_LINKED_TO_TESTPLAN</a>, $msg);
  2791.                     }
  2792.                 }
  2793.                 else
  2794.                 {
  2795.                       $msg = sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#defineMISSING_PLATFORMID_BUT_NEEDED_STR">MISSING_PLATFORMID_BUT_NEEDED_STR</a>,$tplan_info['name'],$tplan_id);  
  2796.                       $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineMISSING_PLATFORMID_BUT_NEEDED">MISSING_PLATFORMID_BUT_NEEDED</a>,$msg_prefix . $msg); 
  2797.                     $status_ok = false;
  2798.                 }
  2799.             }
  2800.         }       
  2801.        if( $status_ok )
  2802.        {
  2803.              // 20100711 - franciscom
  2804.              // Because for TL 1.9 link is done to test plan + platform, logic used 
  2805.              // to understand what to unlink has to be changed.
  2806.              // If same version exists on other platforms
  2807.              //    just add this new record
  2808.              // If other version exists on other platforms
  2809.              //    error -> give message to user
  2810.              //
  2811.              // 
  2812.              
  2813.           // Other versions must be unlinked, because we can only link ONE VERSION at a time
  2814.           // 20090411 - franciscom
  2815.           // As implemented today I'm going to unlink ALL linked versions, then if version
  2816.           // I'm asking to link is already linked, will be unlinked and then relinked.
  2817.           // May be is not wise, IMHO this must be refactored, and give user indication that
  2818.           // requested version already is part of Test Plan.
  2819.           // 
  2820.           $sql = " SELECT TCV.version,TCV.id " . 
  2821.                  " FROM {$this->tables['nodes_hierarchy']} NH, {$this->tables['tcversions']} TCV .
  2822.                  " WHERE NH.parent_id = {$tcase_id.
  2823.                  " AND TCV.id = NH.id ";
  2824.                  
  2825.           $all_tcversions = $this->dbObj->fetchRowsIntoMap($sql,'id');
  2826.           $id_set = array_keys($all_tcversions);
  2827.  
  2828.           // get records regarding all test case versions linked to test plan    
  2829.           $in_clause=implode(",",$id_set);
  2830.           $sql = " SELECT tcversion_id, platform_id, PLAT.name FROM {$this->tables['testplan_tcversions']} TPTCV .
  2831.                  " LEFT OUTER JOIN {$this->tables['platforms']} PLAT ON PLAT.id = platform_id 
  2832.                  " WHERE TPTCV.testplan_id={$tplan_id} AND TPTCV.tcversion_id IN({$in_clause}";
  2833.  
  2834.           $rs = $this->dbObj->fetchMapRowsIntoMap($sql,'tcversion_id','platform_id');
  2835.           
  2836.           $doLink = is_null($rs);
  2837.           if( !$doLink )
  2838.           {
  2839.               if( isset($rs[$target_tcversion[$version_number]['id']]) )
  2840.               {
  2841.                   $plat_keys = array_flip(array_keys($rs[$target_tcversion[$version_number]['id']]));
  2842.                   // need to understand what where the linked platforms.
  2843.                   $platform_id = $this->args[self::$platformIDParamName];
  2844.                   $linkExists = isset($plat_keys[$platform_id]);
  2845.                  $doLink = !$linkExists;
  2846.                   if( $linkExists )
  2847.                   {
  2848.                       $platform_name = $rs[$target_tcversion[$version_number]['id']][$platform_id]['name'];
  2849.                         $msg = sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#defineLINKED_FEATURE_ALREADY_EXISTS_STR">LINKED_FEATURE_ALREADY_EXISTS_STR</a>,$tplan_info['name'],$tplan_id,
  2850.                                        $platform_name, $platform_id);  
  2851.                         $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineLINKED_FEATURE_ALREADY_EXISTS">LINKED_FEATURE_ALREADY_EXISTS</a>,$msg_prefix . $msg); 
  2852.                     $status_ok = false;
  2853.                   }
  2854.               }    
  2855.               else 
  2856.               {
  2857.                   // Other version than requested done is already linked
  2858.                 $doLink = false;
  2859.                 reset($rs);
  2860.                 $linked_tcversion = key($rs);                  
  2861.                   $other_version = $all_tcversions[$linked_tcversion]['version'];
  2862.                     $msg = sprintf(<a href="../TestlinkAPI/_APIErrors.php.html#defineOTHER_VERSION_IS_ALREADY_LINKED_STR">OTHER_VERSION_IS_ALREADY_LINKED_STR</a>,$other_version,$version_number,
  2863.                                    $tplan_info['name'],$tplan_id);
  2864.                     $this->errors[] = new IXR_Error(<a href="../TestlinkAPI/_APIErrors.php.html#defineOTHER_VERSION_IS_ALREADY_LINKED">OTHER_VERSION_IS_ALREADY_LINKED</a>,$msg_prefix . $msg); 
  2865.                 $status_ok = false;
  2866.               }
  2867.               
  2868.           }
  2869.           if( $doLink && $hasPlatforms )
  2870.           {
  2871.              $additional_values[] = $platform_id;
  2872.              $additional_fields[] = 'platform_id';              
  2873.           }
  2874.  
  2875.  
  2876.           if( $doDeleteLinks && count($id_set) > 0 )
  2877.           {
  2878.               $in_clause=implode(",",$id_set);
  2879.               $sql=" DELETE FROM {$this->tables['testplan_tcversions'].
  2880.                    " WHERE testplan_id={$tplan_id}  AND tcversion_id IN({$in_clause}";
  2881.                    $this->dbObj->exec_query($sql);
  2882.           }
  2883.           
  2884.           if( $doLink)
  2885.           {    
  2886.               $fields="testplan_id,tcversion_id,author_id,creation_ts";
  2887.               if( !is_null($additional_fields) )
  2888.               {
  2889.                  $dummy = implode(",",$additional_fields);
  2890.                  $fields .= ',' . $dummy; 
  2891.               }
  2892.               
  2893.               $sql_values="{$tplan_id},{$target_tcversion[$version_number]['id']},.
  2894.                           "{$this->userID},{$this->dbObj->db_now()}";
  2895.               if( !is_null($additional_values) )
  2896.               {
  2897.                  $dummy = implode(",",$additional_values);
  2898.                  $sql_values .= ',' . $dummy; 
  2899.               }
  2900.               
  2901.               $sql=" INSERT INTO {$this->tables['testplan_tcversions']} ({$fields}) VALUES({$sql_values})"; 
  2902.               $this->dbObj->exec_query($sql);
  2903.  
  2904.               $op_result['feature_id']=$this->dbObj->insert_id($this->tables['testplan_tcversions']);
  2905.  
  2906.           }
  2907.           $op_result['operation']=$operation;
  2908.           $op_result['status']=true;
  2909.           $op_result['message']='';
  2910.        }
  2911.        
  2912.        return ($status_ok ? $op_result : $this->errors);
  2913.      }    
  2914.  
  2915.   
  2916.      /**
  2917.       * get set of test suites AT TOP LEVEL of tree on a Test Project
  2918.       *
  2919.       * @param args['testprojectid']
  2920.       *    
  2921.       * @return array
  2922.       *
  2923.       */
  2924.    public function getFirstLevelTestSuitesForTestProject($args)
  2925.    {
  2926.         $msg_prefix="(" .__FUNCTION__ . ") - ";
  2927.         $status_ok=true;
  2928.         $this->_setArgs($args);
  2929.  
  2930.         $checkFunctions array('authenticate','checkTestProjectID');
  2931.         $status_ok=$this->_runChecks($checkFunctions,$msg_prefix);
  2932.  
  2933.         if$status_ok )
  2934.         {
  2935.             $result = $this->tprojectMgr->get_first_level_test_suites($this->args[self::$testProjectIDParamName]);
  2936.             ifis_null($result) )
  2937.             {
  2938.                 $status_ok=false;
  2939.                 $tproject_info = $this->tprojectMgr->get_by_id($this->args[self::$testProjectIDParamName]);
  2940.                 $msg=$msg_prefix sprintf(TPROJECT_IS_EMPTY_STR,$tproject_info['name']);
  2941.                 $this->errors[new IXR_ERROR(TPROJECT_IS_EMPTY,$msg)
  2942.             } 
  2943.         }
  2944.         return $status_ok ? $result : $this->errors;       
  2945.    }
  2946.    
  2947.  
  2948.    /**
  2949.     *  Assign Requirements to a test case 
  2950.     *  we can assign multiple requirements.
  2951.     *  Requirements can belong to different Requirement Spec
  2952.     *         
  2953.     *  @param struct $args
  2954.     *  @param string $args["devKey"]
  2955.     *  @param int $args["testcaseexternalid"]
  2956.     *  @param int $args["testprojectid"] 
  2957.     *  @param string $args["requirements"] 
  2958.     *                array(array('req_spec' => 1,'requirements' => array(2,4)),
  2959.     *                array('req_spec' => 3,'requirements' => array(22,42))
  2960.     *
  2961.     */
  2962.    public function assignRequirements($args)
  2963.    {
  2964.         $operation=__FUNCTION__;
  2965.         $msg_prefix="({$operation}) - ";
  2966.         $status_ok=true;
  2967.         $this->_setArgs($args);
  2968.         $resultInfo=array();
  2969.         $checkFunctions array('authenticate','checkTestProjectID','checkTestCaseIdentity');       
  2970.         $status_ok=$this->_runChecks($checkFunctions,$msg_prefix);
  2971.  
  2972.         if$status_ok )
  2973.         {
  2974.             $ret = $this->checkTestCaseAncestry();
  2975.             $status_ok=$ret['status_ok'];
  2976.             if!$status_ok )
  2977.             {
  2978.                 $this->errors[new IXR_Error($ret['error_code']$msg_prefix $ret['error_msg'])
  2979.             }           
  2980.         }
  2981.        
  2982.         if( $status_ok )
  2983.         {
  2984.             $ret = $this->checkReqSpecQuality();
  2985.             $status_ok=$ret['status_ok'];
  2986.             if!$status_ok )
  2987.             {
  2988.                 $this->errors[new IXR_Error($ret['error_code']$msg_prefix $ret['error_msg'])
  2989.             }           
  2990.         }
  2991.        
  2992.         if($status_ok)
  2993.         {
  2994.             // assignment
  2995.             // Note: when test case identity is checked this args key is setted
  2996.             //       this does not means that this mut be present on method call.
  2997.             //
  2998.             $tcase_id=$this->args[self::$testCaseIDParamName];
  2999.             foreach($this->args[self::$requirementsParamNameas $item)
  3000.             {
  3001.                 foreach($item['requirements'] as $req_id)
  3002.                 {
  3003.                      $this->reqMgr->assign_to_tcase($req_id,$tcase_id);
  3004.                 }          
  3005.             }
  3006.                  $resultInfo[] = array("operation" => $operation,
  3007.                                         "status" => true, "id" => -1, 
  3008.                                        "additionalInfo" => '',
  3009.                                      "message" => GENERAL_SUCCESS_STR);
  3010.         }
  3011.         
  3012.         return ($status_ok ? $resultInfo : $this->errors);
  3013.   }
  3014.  
  3015.  
  3016.   /**
  3017.    * checks if a test case belongs to test project
  3018.    *
  3019.    * @param string $messagePrefix used to be prepended to error message
  3020.    * 
  3021.    * @return map with following keys
  3022.    *             boolean map['status_ok']
  3023.    *             string map['error_msg']
  3024.    *             int map['error_code']
  3025.    */
  3026.   protected function checkTestCaseAncestry($messagePrefix='')
  3027.   {
  3028.       $ret=array('status_ok' => true, 'error_msg' => '' , 'error_code' => 0);
  3029.       $tproject_id=$this->args[self::$testProjectIDParamName];
  3030.       $tcase_id=$this->args[self::$testCaseIDParamName];
  3031.       $tcase_external_id=$this->args[self::$testCaseExternalIDParamName];
  3032.       $tcase_tproject_id=$this->tcaseMgr->get_testproject($tcase_id);
  3033.       
  3034.       if($tcase_tproject_id != $tproject_id)
  3035.       {
  3036.           $status_ok=false;
  3037.           $tcase_info=$this->tcaseMgr->get_by_id($tcase_id);
  3038.           $tproject_info $this->tprojectMgr->get_by_id($tproject_id);
  3039.           $msg $messagePrefix sprintf(TCASE_TPROJECT_KO_STR,$tcase_external_id,$tcase_info[0]['name'],
  3040.                                           $tproject_info['name'],$tproject_id);  
  3041.           $ret=array('status_ok' => false'error_msg' => $msg 'error_code' => TCASE_TPROJECT_KO);                                               
  3042.       } 
  3043.       return $ret;
  3044.   } // function end
  3045.  
  3046.   /*
  3047.    *  checks Quality of requirements spec
  3048.    *  checks done on 
  3049.    *  Requirements Specification is present on system
  3050.    *  Requirements Specification belongs to test project
  3051.    * 
  3052.    * @return map with following keys
  3053.    *             boolean map['status_ok']
  3054.    *             string map['error_msg']
  3055.    *             int map['error_code']
  3056.    */
  3057.   protected function checkReqSpecQuality()
  3058.   {
  3059.       $ret=array('status_ok' => true, 'error_msg' => '' , 'error_code' => 0);
  3060.       $tproject_id=$this->args[self::$testProjectIDParamName];
  3061.       $nodes_types $this->tprojectMgr->tree_manager->get_available_node_types();
  3062.           
  3063.       foreach($this->args[self::$requirementsParamNameas $item)
  3064.       {
  3065.           // does it exist ?
  3066.           $req_spec_id=$item['req_spec'];
  3067.           $reqspec_info=$this->reqSpecMgr->get_by_id($req_spec_id);      
  3068.           if(is_null($reqspec_info))
  3069.           {
  3070.               $status_ok=false;
  3071.               $msg = sprintf(REQSPEC_KO_STR,$req_spec_id);
  3072.               $error_code=REQSPEC_KO;
  3073.               break;  
  3074.           }       
  3075.           
  3076.           // does it belongs to test project ?
  3077.           $a_path=$this->tprojectMgr->tree_manager->get_path($req_spec_id);
  3078.           $req_spec_tproject_id=$a_path[0]['parent_id'];
  3079.           if($req_spec_tproject_id != $tproject_id)
  3080.           {
  3081.               $status_ok=false;
  3082.               $tproject_info = $this->tprojectMgr->get_by_id($tproject_id);
  3083.               $msg sprintf(REQSPEC_TPROJECT_KO_STR,$reqspec_info['title'],$req_spec_id,
  3084.                                                      $tproject_info['name'],$tproject_id);  
  3085.               $error_code=REQSPEC_TPROJECT_KO;
  3086.               break;  
  3087.           }
  3088.           
  3089.           // does this specification have requirements ?
  3090.           $my_requirements = $this->tprojectMgr->tree_manager->get_subtree_list($req_spec_id,$nodes_types['requirement']);
  3091.           $status_ok (trim($my_requirements!= "");
  3092.           if(!$status_ok)
  3093.           {
  3094.               $msg = sprintf(REQSPEC_IS_EMPTY_STR,$reqspec_info['title'],$req_spec_id);
  3095.               $error_code = REQSPEC_IS_EMPTY;
  3096.               break;
  3097.           }
  3098.           
  3099.           // if everything is OK, analise requirements
  3100.           if( $status_ok )
  3101.           {
  3102.               $dummy=array_flip(explode(",",$my_requirements));
  3103.               foreach($item['requirements'] as $req_id)
  3104.               {
  3105.                   if( !isset($dummy[$req_id]) )
  3106.                   {
  3107.                       $status_ok=false;
  3108.                       $req_info = $this->reqMgr->get_by_id($req_id,requirement_mgr::LATEST_VERSION);
  3109.                       
  3110.                       ifis_null($req_info) )
  3111.                       {
  3112.                           $msg = sprintf(REQ_KO_STR,$req_id);
  3113.                           $error_code=REQ_KO;
  3114.                       }
  3115.                       else 
  3116.                       {  
  3117.                             $req_info = $req_inf[0];
  3118.                           $msg = sprintf(REQ_REQSPEC_KO_STR,$req_info['req_doc_id'],$req_info['title'],$req_id,
  3119.                                          $reqspec_info['title'],$req_spec_id);
  3120.                           $error_code=REQ_REQSPEC_KO;
  3121.                       }
  3122.                       break;
  3123.                   }      
  3124.               }
  3125.           }
  3126.           
  3127.           if( !$status_ok )
  3128.           {
  3129.               break;
  3130.           }
  3131.       }
  3132.  
  3133.       if(!$status_ok)
  3134.       {
  3135.           $ret=array('status_ok' => false, 'error_msg' => $msg , 'error_code' => $error_code);                                               
  3136.       } 
  3137.       return $ret;
  3138.   }
  3139.  
  3140.     /**
  3141.      * Insert record into execution_bugs table
  3142.      * @param  int    $executionID     
  3143.      * @param  string $bugID
  3144.      * @return boolean
  3145.      * @access protected
  3146.      * contribution by hnishiyama
  3147.     **/
  3148.     protected function _insertExecutionBug($executionID, $bugID)
  3149.     {
  3150.         // Check for existence of executionID
  3151.         $sql="SELECT id FROM {$this->tables['executions']} WHERE id={$executionID}";
  3152.         $rs=$this->dbObj->fetchRowsIntoMap($sql,'id');
  3153.         $status_ok !(is_null($rs|| $bugID == '');        
  3154.         if($status_ok)
  3155.         {
  3156.             $safeBugID=$this->dbObj->prepare_string($bugID);
  3157.                $sql="SELECT execution_id FROM {$this->tables['execution_bugs']} " .  
  3158.                  "WHERE execution_id={$executionID} AND bug_id='{$safeBugID}'";
  3159.         
  3160.             if( is_null($this->dbObj->fetchRowsIntoMap($sql'execution_id')) )
  3161.             {
  3162.                 $sql = "INSERT INTO {$this->tables['execution_bugs']} " .
  3163.                        "(execution_id,bug_id) VALUES({$executionID},'{$safeBugID}')";
  3164.                 $result = $this->dbObj->exec_query($sql)
  3165.                 $status_ok=$result true false ;
  3166.             }
  3167.         }
  3168.         return $status_ok;
  3169.     }
  3170.  
  3171.  
  3172. /**
  3173.  *  get bugs linked to an execution ID
  3174.  * @param  int $execution_id     
  3175.  *
  3176.  * @return map indexed by bug_id
  3177.  */
  3178. protected function _getBugsForExecutionId($execution_id)
  3179. {
  3180.     $rs=null;
  3181.     if( !is_null($execution_id) && $execution_id <> '' )
  3182.     {
  3183.         $sql = "SELECT execution_id,bug_id, B.name AS build_name " .
  3184.                "FROM {$this->tables['execution_bugs']} ," .
  3185.                " {$this->tables['executions']} E, {$this->tables['builds']} B ".
  3186.                "WHERE execution_id={$execution_id} " .
  3187.                "AND   execution_id=E.id " .
  3188.                "AND   E.build_id=B.id " .
  3189.                "ORDER BY B.name,bug_id";
  3190.         $rs=$this->dbObj->fetchRowsIntoMap($sql,'bug_id');
  3191.     }
  3192.     return $rs;   
  3193. }
  3194.  
  3195.  
  3196.  
  3197. /**
  3198.  * Gets attachments for specified test case.
  3199.  * The attachment file content is Base64 encoded. To save the file to disk in client,
  3200.  * Base64 decode the content and write file in binary mode. 
  3201.  * 
  3202.  * @param struct $args
  3203.  * @param string $args["devKey"] Developer key
  3204.  * @param int $args["testcaseid"]: optional, if does not is present           
  3205.  *                                 testcaseexternalid must be present
  3206.  *
  3207.  * @param int $args["testcaseexternalid"]: optional, if does not is present           
  3208.  *                                         testcaseid must be present
  3209.  * 
  3210.  * @return mixed $resultInfo
  3211.  */
  3212. public function getTestCaseAttachments($args)
  3213. {
  3214.     $this->_setArgs($args);
  3215.     $attachments=null;
  3216.     $checkFunctions array('authenticate','checkTestCaseIdentity');       
  3217.     $status_ok=$this->_runChecks($checkFunctions&& $this->userHasRight("mgt_view_tc");
  3218.     
  3219.     if($status_ok)
  3220.     {        
  3221.         $tcase_id = $this->args[self::$testCaseIDParamName];
  3222.         $attachmentRepository tlAttachmentRepository::create($this->dbObj);
  3223.         $attachmentInfos $attachmentRepository->getAttachmentInfosFor($tcase_id,"nodes_hierarchy");
  3224.         
  3225.         if ($attachmentInfos)
  3226.         {
  3227.             foreach ($attachmentInfos as $attachmentInfo)
  3228.             {
  3229.                 $aID = $attachmentInfo["id"];
  3230.                 $content = $attachmentRepository->getAttachmentContent($aID$attachmentInfo);
  3231.                 
  3232.                 if ($content != null)
  3233.                 {
  3234.                     $attachments[$aID]["id"] = $aID;
  3235.                     $attachments[$aID]["name"] = $attachmentInfo["file_name"];
  3236.                     $attachments[$aID]["file_type"] = $attachmentInfo["file_type"];
  3237.                     $attachments[$aID]["title"] = $attachmentInfo["title"];
  3238.                     $attachments[$aID]["date_added"] = $attachmentInfo["date_added"];
  3239.                     $attachments[$aID]["content"] = base64_encode($content);
  3240.                 }
  3241.             }
  3242.         }
  3243.     }
  3244.   return $status_ok ? $attachments : $this->errors;
  3245. }
  3246.  
  3247.  
  3248.     /**
  3249.      * create a test suite
  3250.      * 
  3251.      * @param struct $args
  3252.      * @param string $args["devKey"]
  3253.      * @param int $args["testprojectid"]
  3254.      * @param string $args["testsuitename"]
  3255.      * @param string $args["details"]
  3256.      * @param int $args["parentid"] optional, if do not provided means test suite must be top level.
  3257.      * @param int $args["order"] optional. Order inside parent container
  3258.      * @param int $args["checkduplicatedname"] optional, default true.
  3259.      *                                          will check if there are siblings with same name.
  3260.      *
  3261.      * @param int $args["actiononduplicatedname"] optional
  3262.      *                                            applicable only if $args["checkduplicatedname"]=true
  3263.      *                                            what to do if already a sibling exists with same name.
  3264.      *     
  3265.      * @return mixed $resultInfo
  3266.      */
  3267.     public function createTestSuite($args)
  3268.     {
  3269.         $result=array();
  3270.         $this->_setArgs($args);
  3271.         $operation=__FUNCTION__;
  3272.         $msg_prefix="({$operation}) - ";
  3273.         $checkFunctions = array('authenticate','checkTestSuiteName','checkTestProjectID');
  3274.         $status_ok=$this->_runChecks($checkFunctions,$msg_prefix&& $this->userHasRight("mgt_modify_tc");
  3275.       
  3276.         if$status_ok )
  3277.         {
  3278.             // Optional parameters
  3279.             $opt=array(self::$orderParamName => testsuite::DEFAULT_ORDER,
  3280.                        self::$checkDuplicatedNameParamName => testsuite::CHECK_DUPLICATE_NAME,
  3281.                        self::$actionOnDuplicatedNameParamName => 'block');
  3282.             
  3283.             foreach($opt as $key => $value)
  3284.             {
  3285.                 if($this->_isParamPresent($key))
  3286.                 {
  3287.                     $opt[$key]=$this->args[$key];      
  3288.                 }   
  3289.             }
  3290.         }
  3291.  
  3292.         if($status_ok)
  3293.         {
  3294.             $parent_id = $args[self::$testProjectIDParamName];  
  3295.             $tprojectInfo=$this->tprojectMgr->get_by_id($args[self::$testProjectIDParamName]);
  3296.             $tsuiteMgr new testsuite($this->dbObj);
  3297.               if$this->_isParamPresent(self::$parentIDParamName) )
  3298.               {
  3299.                   $parent_id = $args[self::$parentIDParamName];
  3300.  
  3301.                 // if parentid exists it must:
  3302.                 // be a test suite id 
  3303.                   $node_info = $tsuiteMgr->get_by_id($args[self::$parentIDParamName]);
  3304.                   if!($status_ok=!is_null($node_info)) )
  3305.                   {
  3306.                    $msg=sprintf(INVALID_PARENT_TESTSUITEID_STR,
  3307.                                 $args[self::$parentIDParamName],$args[self::$testSuiteNameParamName]);
  3308.                    $this->errors[new IXR_Error(INVALID_PARENT_TESTSUITEID,$msg_prefix $msg);
  3309.                 }
  3310.               
  3311.                 if($status_ok)
  3312.                 {
  3313.                    // Must belong to target test project
  3314.                    $root_node_id=$tsuiteMgr->getTestProjectFromTestSuite($args[self::$parentIDParamName],null);
  3315.                   
  3316.                    if!($status_ok ($root_node_id == $args[self::$testProjectIDParamName])) )
  3317.                    {
  3318.                      $msg=sprintf(TESTSUITE_DONOTBELONGTO_TESTPROJECT_STR,$args[self::$parentIDParamName],
  3319.                                   $tprojectInfo['name'],$args[self::$testProjectIDParamName]);
  3320.                      $this->errors[new IXR_Error(TESTSUITE_DONOTBELONGTO_TESTPROJECT,$msg_prefix $msg);
  3321.                    }
  3322.                 }
  3323.               } 
  3324.       }
  3325.       
  3326.       if($status_ok)
  3327.       {
  3328.           $op=$tsuiteMgr->create($parent_id,$args[self::$testSuiteNameParamName],
  3329.                                  $args[self::$detailsParamName],$opt[self::$orderParamName],
  3330.                                  $opt[self::$checkDuplicatedNameParamName],
  3331.                                  $opt[self::$actionOnDuplicatedNameParamName]);
  3332.           
  3333.           if( ($status_ok $op['status_ok']) )
  3334.           {
  3335.               $op['status'] = $op['status_ok'] ? true : false;
  3336.               $op['operation'] = $operation;
  3337.               $op['additionalInfo'] = '';
  3338.               $op['message'] = $op['msg'];
  3339.               unset($op['msg']);
  3340.               unset($op['status_ok']);
  3341.               $result[]=$op;  
  3342.           }
  3343.           else
  3344.           {
  3345.               $op['msg']=sprintf($op['msg'],$args[self::$testSuiteNameParamName]);
  3346.               $this->errors=$op;   
  3347.           }
  3348.       }
  3349.       
  3350.             return $status_ok ? $result : $this->errors;
  3351.     }
  3352.  
  3353.  
  3354.     /**
  3355.      * test suite name provided is valid 
  3356.      * 
  3357.      * @param string $messagePrefix used to be prepended to error message
  3358.      *
  3359.      * @return boolean
  3360.      * @access protected
  3361.      */        
  3362.     protected function checkTestSuiteName($messagePrefix='')
  3363.     {
  3364.         $status_ok=isset($this->args[self::$testSuiteNameParamName]true false;
  3365.         if($status_ok)
  3366.         {
  3367.               $name = $this->args[self::$testSuiteNameParamName];
  3368.               if(!is_string($name))
  3369.               {
  3370.                 $msg=$messagePrefix . TESTSUITENAME_NOT_STRING_STR;
  3371.                   $this->errors[new IXR_Error(TESTSUITENAME_NOT_STRING$msg);
  3372.                   $status_ok=false;
  3373.               }
  3374.         }
  3375.         else
  3376.         {
  3377.                  $this->errors[new IXR_Error(NO_TESTSUITENAME$messagePrefix NO_TESTSUITENAME_STR);
  3378.         }
  3379.         return $status_ok;
  3380.     }
  3381.  
  3382.  
  3383.  
  3384.  
  3385.     /**
  3386.      * Gets info about target test project
  3387.      *
  3388.      * @param struct $args
  3389.      * @param string $args["devKey"]
  3390.      * @param string $args["testprojectname"]     
  3391.      * @return mixed $resultInfo            
  3392.      * @access public
  3393.      */        
  3394.     public function getTestProjectByName($args)
  3395.     {
  3396.         $msg_prefix="(" .__FUNCTION__ . ") - ";
  3397.            $status_ok=true;
  3398.         $this->_setArgs($args);        
  3399.         if($this->authenticate())
  3400.         {
  3401.             $status_ok=false; 
  3402.             if( $this->_isParamPresent(self::$testProjectNameParamName,$msg_prefix,self::SET_ERROR) )
  3403.             {
  3404.                 $name=trim($this->args[self::$testProjectNameParamName]);
  3405.                 $check_op=$this->tprojectMgr->checkNameExistence($name);
  3406.                 $not_found=$check_op['status_ok'];     
  3407.                 $status_ok=!$not_found;
  3408.                 if($not_found)      
  3409.                 {
  3410.                     $status_ok=false;
  3411.                     $msg = $msg_prefix . sprintf(TESTPROJECTNAME_DOESNOT_EXIST_STR,$name);
  3412.                     $this->errors[new IXR_Error(TESTPROJECTNAME_DOESNOT_EXIST$msg);
  3413.                 }
  3414.             }
  3415.         }
  3416.         if($status_ok)
  3417.         {
  3418.             $info=$this->tprojectMgr->get_by_name($name);            
  3419.         }
  3420.         return $status_ok ? $info : $this->errors;
  3421.     }
  3422.  
  3423.  
  3424.     /**
  3425.      * Gets info about target test project
  3426.      *
  3427.      * @param struct $args
  3428.      * @param string $args["devKey"]
  3429.      * @param string $args["testprojectname"]     
  3430.      * @param string $args["testplanname"]     
  3431.      * @return mixed $resultInfo            
  3432.      * @access public
  3433.      */        
  3434.     public function getTestPlanByName($args)
  3435.     {
  3436.         $msg_prefix="(" .__FUNCTION__ . ") - ";
  3437.            $status_ok=true;
  3438.         $this->_setArgs($args);        
  3439.         if($this->authenticate())
  3440.         {
  3441.             $keys2check = array(self::$testPlanNameParamName,
  3442.                                 self::$testProjectNameParamName);
  3443.             foreach($keys2check as $key)
  3444.             {
  3445.                 $names[$key]=$this->_isParamPresent($key,$msg_prefix,self::SET_ERRORtrim($this->args[$key]'';
  3446.                 if($names[$key]=='')
  3447.                 {
  3448.                     $status_ok=false;    
  3449.                     breack;
  3450.                 }
  3451.             }
  3452.         }
  3453.         
  3454.         if($status_ok)
  3455.         {
  3456.             // need to check name existences
  3457.             $name=$names[self::$testProjectNameParamName];
  3458.             $check_op=$this->tprojectMgr->checkNameExistence($name);
  3459.             $not_found=$check_op['status_ok'];     
  3460.             $status_ok=!$not_found;
  3461.             if($not_found)      
  3462.             {
  3463.                 $status_ok=false;
  3464.                 $msg = $msg_prefix . sprintf(TESTPROJECTNAME_DOESNOT_EXIST_STR,$name);
  3465.                 $this->errors[new IXR_Error(TESTPROJECTNAME_DOESNOT_EXIST$msg);
  3466.             }
  3467.             else
  3468.             {
  3469.                 $tprojectInfo=current($this->tprojectMgr->get_by_name($name));
  3470.             }
  3471.         }
  3472.         
  3473.         if($status_ok)
  3474.         {
  3475.             $name=trim($names[self::$testPlanNameParamName]);
  3476.             $info = $this->tplanMgr->get_by_name($name,$tprojectInfo['id']);
  3477.             if!($status_ok=!is_null($info)) )
  3478.             {
  3479.                 $msg = $msg_prefix . sprintf(TESTPLANNAME_DOESNOT_EXIST_STR,$name,$tprojectInfo['name']);
  3480.                 $this->errors[new IXR_Error(TESTPLANNAME_DOESNOT_EXIST$msg);
  3481.             
  3482.             }
  3483.         }
  3484.  
  3485.         return $status_ok ? $info : $this->errors;
  3486.     }
  3487.  
  3488.  
  3489. /**
  3490. * get test case specification using external ir internal id
  3491. * @param struct $args
  3492. * @param string $args["devKey"]
  3493. * @param int $args["testcaseid"]: optional, if does not is present           
  3494. *                                 testcaseexternalid must be present
  3495. *
  3496. * @param int $args["testcaseexternalid"]: optional, if does not is present           
  3497. *                                         testcaseid must be present
  3498. * @param int $args["version"]: optional, if does not is present max version number will be
  3499. *                                        retuned
  3500. *
  3501. * @return mixed $resultInfo
  3502. */
  3503. public function getTestCase($args)
  3504. {
  3505.     $msg_prefix="(" .__FUNCTION__ . ") - ";
  3506.     $status_ok=true;
  3507.     $this->_setArgs($args);
  3508.     
  3509.     $checkFunctions array('authenticate','checkTestCaseIdentity');       
  3510.     $status_ok=$this->_runChecks($checkFunctions,$msg_prefix&& $this->userHasRight("mgt_view_tc");       
  3511.     $version_id=testcase::LATEST_VERSION;
  3512.     $version_number=-1;
  3513.  
  3514.     if$status_ok )
  3515.     {            
  3516.         // check optional arguments
  3517.         if( $this->_isParamPresent(self::$versionNumberParamName) )
  3518.         {
  3519.             if( ($status_ok=$this->checkTestCaseVersionNumber()) )
  3520.             {
  3521.                 $version_id=null;
  3522.                 $version_number=$this->args[self::$versionNumberParamName];
  3523.             }
  3524.         }
  3525.     }
  3526.     
  3527.     if( $status_ok )
  3528.     {            
  3529.         $testCaseMgr = new testcase($this->dbObj);
  3530.         $id=$this->args[self::$testCaseIDParamName];
  3531.         
  3532.         $result $testCaseMgr->get_by_id($id,$version_id,'ALL','ALL',$version_number);            
  3533.         if(== sizeof($result))
  3534.         {
  3535.             $status_ok=false;
  3536.             $this->errors[new IXR_ERROR(NO_TESTCASE_FOUND
  3537.                                             $msg_prefix NO_TESTCASE_FOUND_STR);
  3538.             return $this->errors;
  3539.         }
  3540.     }
  3541.  
  3542.     return $status_ok ? $result : $this->errors
  3543. }
  3544.  
  3545.  
  3546.  
  3547.     /**
  3548.      * create a test plan
  3549.      * 
  3550.      * @param struct $args
  3551.      * @param string $args["devKey"]
  3552.      * @param int $args["testplanname"]
  3553.      * @param int $args["testprojectname"]
  3554.      * @param string $args["notes"], optional
  3555.      * @param string $args["active"], optional default value 1
  3556.      * @param string $args["public"], optional default value 1
  3557.      *     
  3558.      * @return mixed $resultInfo
  3559.      * @internal revision
  3560.      *    20100704 - franciscom - BUGID 3565
  3561.      */
  3562.     public function createTestPlan($args)
  3563.     {
  3564.         $this->_setArgs($args);
  3565.         $status_ok false;    
  3566.         $msg_prefix="(" . __FUNCTION__ . ") - ";
  3567.  
  3568.         if($this->authenticate(&& $this->userHasRight("mgt_modify_product"))
  3569.         {
  3570.             $keys2check = array(self::$testPlanNameParamName,
  3571.                                 self::$testProjectNameParamName);
  3572.         
  3573.             $status_ok = true;
  3574.             foreach($keys2check as $key)
  3575.             {
  3576.                 $names[$key]=$this->_isParamPresent($key,$msg_prefix,self::SET_ERRORtrim($this->args[$key]'';
  3577.                 if($names[$key]=='')
  3578.                 {
  3579.                     $status_ok=false;    
  3580.                     break;
  3581.                 }
  3582.             }
  3583.         }
  3584.  
  3585.         if( $status_ok )
  3586.         {
  3587.             $name=trim($this->args[self::$testProjectNameParamName]);
  3588.             $check_op=$this->tprojectMgr->checkNameExistence($name);
  3589.             $status_ok=!$check_op['status_ok'];     
  3590.             if($status_ok
  3591.             {
  3592.                 $tprojectInfo=current($this->tprojectMgr->get_by_name($name));
  3593.             }
  3594.             else     
  3595.             {
  3596.                 $status_ok=false;
  3597.                 $msg = $msg_prefix . sprintf(TESTPROJECTNAME_DOESNOT_EXIST_STR,$name);
  3598.                 $this->errors[new IXR_Error(TESTPROJECTNAME_DOESNOT_EXIST$msg);
  3599.             }
  3600.         }
  3601.  
  3602.         if( $status_ok )
  3603.         {
  3604.             $name=trim($names[self::$testPlanNameParamName]);
  3605.             $info = $this->tplanMgr->get_by_name($name,$tprojectInfo['id']);
  3606.             $status_ok=is_null($info);
  3607.             
  3608.             if!($status_ok=is_null($info)))
  3609.             {
  3610.                 $msg = $msg_prefix . sprintf(TESTPLANNAME_ALREADY_EXISTS_STR,$name,$tprojectInfo['name']);
  3611.                 $this->errors[new IXR_Error(TESTPLANNAME_ALREADY_EXISTS$msg);
  3612.             }
  3613.         }
  3614.  
  3615.         if( $status_ok )
  3616.         {
  3617.             $keys2check = array(self::$activeParamName => 1,self::$publicParamName => 1,
  3618.                                 self::$noteParamName => '');
  3619.               foreach($keys2check as $key => $value)
  3620.               {
  3621.                   $optional[$key]=$this->_isParamPresent($keytrim($this->args[$key]$value;
  3622.               }
  3623.             $retval = $this->tplanMgr->create(htmlspecialchars($name),
  3624.                                               htmlspecialchars($optional[self::$noteParamName]),
  3625.                                               $tprojectInfo['id'],$optional[self::$activeParamName],
  3626.                                               $optional[self::$publicParamName]);
  3627.  
  3628.             $resultInfo array();
  3629.             $resultInfo[]array("operation" => __FUNCTION__,"additionalInfo" => null,
  3630.                                  "status" => true"id" => $retval"message" => GENERAL_SUCCESS_STR);
  3631.         }
  3632.  
  3633.         return $status_ok ? $resultInfo : $this->errors;
  3634.     } // public function createTestPlan
  3635.  
  3636.     /**
  3637.      * Gets full path from the given node till the top using nodes_hierarchy_table
  3638.      *
  3639.      * @param struct $args
  3640.      * @param string $args["devKey"]
  3641.      * @param mixed $args["nodeID"] can be just a single node or an array of INTERNAL (DB) ID
  3642.      * @return mixed $resultInfo            
  3643.      * @access public
  3644.      *
  3645.      * @internal revision
  3646.      * BUGID 3993
  3647.      * $args["nodeID"] can be just a single node or an array
  3648.      * when path can not be found same date structure will be returned, that on situations
  3649.      * where all is ok, but content for KEY(nodeID) will be NULL instead of rising ERROR  
  3650.      *
  3651.      */        
  3652.     public function getFullPath($args)
  3653.     {
  3654.           $this->_setArgs($args);
  3655.           $operation=__FUNCTION__;
  3656.         $msg_prefix="({$operation}) - ";
  3657.         $checkFunctions = array('authenticate');
  3658.         $status_ok=$this->_runChecks($checkFunctions,$msg_prefix&& 
  3659.                    $this->_isParamPresent(self::$nodeIDParamName,$msg_prefix,self::SET_ERROR;
  3660.       
  3661.         if$status_ok )
  3662.         {
  3663.             $nodeIDSet = $this->args[self::$nodeIDParamName];
  3664.             
  3665.             // if is array => OK
  3666.             if!($workOnSet is_array($nodeIDSet)) && (!is_int($nodeIDSet|| $nodeIDSet <= 0) )
  3667.             {
  3668.                 $msg = $msg_prefix . sprintf(NODEID_INVALID_DATA_TYPE);
  3669.                 $this->errors[new IXR_Error(NODEID_INVALID_DATA_TYPE$msg);
  3670.                 $status_ok=false;
  3671.             } 
  3672.             
  3673.             if( $status_ok && $workOnSet)
  3674.             {
  3675.                 // do check on each item on set
  3676.                 foreach($nodeIDSet as $itemID)
  3677.                 {
  3678.                     if(!is_int($itemID) || $itemID <= 0) 
  3679.             {
  3680.                         $msg = $msg_prefix . sprintf(NODEID_IS_NOT_INTEGER_STR,$itemID);
  3681.                 $this->errors[new IXR_Error(NODEID_IS_NOT_INTEGER$msg);
  3682.                 $status_ok=false;
  3683.             } 
  3684.         }
  3685.             }
  3686.             
  3687.         }
  3688.         
  3689.         if( $status_ok )
  3690.         {
  3691.             // IMPORTANT NOTICE:
  3692.             // (may be a design problem but ..)
  3693.             // If $nodeIDSet is an array and for one of items path can not be found
  3694.             // get_full_path_verbose() returns null, no matter if for other items
  3695.             // information is available
  3696.             // 
  3697.             $full_path = $this->tprojectMgr->tree_manager->get_full_path_verbose($nodeIDSet);
  3698.         }
  3699.         return $status_ok ? $full_path : $this->errors;
  3700.     }
  3701.  
  3702.     /**
  3703.       * 
  3704.      *
  3705.      */
  3706.     protected function _insertCustomFieldExecValues($executionID)
  3707.     {
  3708.         // // Check for existence of executionID   
  3709.         $status_ok=true;
  3710.         $sql="SELECT id FROM {$this->tables['executions']} WHERE id={$executionID}";
  3711.         $rs=$this->dbObj->fetchRowsIntoMap($sql,'id');
  3712.         // 
  3713.         $cfieldSet=$this->args[self::$customFieldsParamName];
  3714.         $tprojectID=$this->tcaseMgr->get_testproject($this->args[self::$testCaseIDParamName]);
  3715.         $tplanID=$this->args[self::$testPlanIDParamName];
  3716.         $cfieldMgr=$this->tprojectMgr->cfield_mgr;        
  3717.         $cfieldsMap $cfieldMgr->get_linked_cfields_at_execution($tprojectID1,'testcase',
  3718.                                                                   null,null,null,'name');
  3719.         $status_ok !(is_null($rs|| is_null($cfieldSet|| count($cfieldSet== 0);        
  3720.         $cfield4write null;
  3721.         if$status_ok && !is_null($cfieldsMap) )
  3722.         {
  3723.             foreach($cfieldSet as $name => $value)
  3724.             {
  3725.                  if( isset($cfieldsMap[$name]) )
  3726.                  {
  3727.                      $cfield4write[$cfieldsMap[$name]['id']] = array("type_id"  => $cfieldsMap[$name]['type'],
  3728.                                                               "cf_value" => $value);
  3729.                    }
  3730.              }    
  3731.              if( !is_null($cfield4write) )
  3732.              {
  3733.                  $cfieldMgr->execution_values_to_db($cfield4write,$this->tcVersionID,$executionID,$tplanID,
  3734.                                                     null,'write-through');
  3735.              }
  3736.         }        
  3737.         return $status_ok;
  3738.     }
  3739.  
  3740.  
  3741.  
  3742.      /**
  3743.      * delete an execution
  3744.      *
  3745.      * @param struct $args
  3746.      * @param string $args["devKey"]
  3747.      * @param int $args["executionid"]
  3748.      *
  3749.      * @return mixed $resultInfo 
  3750.      *                 [status]    => true/false of success
  3751.      *                 [id]          => result id or error code
  3752.      *                 [message]    => optional message for error message string
  3753.      * @access public
  3754.      */    
  3755.      public function deleteExecution($args)
  3756.      {        
  3757.         $resultInfo = array();
  3758.         $operation=__FUNCTION__;
  3759.         $msg_prefix="({$operation}) - ";
  3760.         $execCfg = config_get('exec_cfg');
  3761.  
  3762.         $this->_setArgs($args);              
  3763.         $resultInfo[0]["status"false;
  3764.         
  3765.         $checkFunctions array('authenticate','checkExecutionID');       
  3766.         $status_ok $this->_runChecks($checkFunctions,$msg_prefix);       
  3767.     
  3768.         // Important userHasRight sets error object
  3769.         //
  3770.         $status_ok ($status_ok && $this->userHasRight("testplan_execute"));    
  3771.         if($status_ok)
  3772.         {            
  3773.             if( $execCfg->can_delete_execution )  
  3774.             {
  3775.                 $this->tcaseMgr->deleteExecution($args[self::$executionIDParamName]);            
  3776.                 $resultInfo[0]["status"true;
  3777.                 $resultInfo[0]["id"$args[self::$executionIDParamName];    
  3778.                 $resultInfo[0]["message"GENERAL_SUCCESS_STR;
  3779.                 $resultInfo[0]["operation"$operation;
  3780.             }
  3781.             else
  3782.             {
  3783.                 $status_ok = false;
  3784.                 $this->errors[new IXR_Error(CFG_DELETE_EXEC_DISABLED
  3785.                                                 CFG_DELETE_EXEC_DISABLED_STR);
  3786.             }
  3787.         }
  3788.  
  3789.         return $status_ok ? $resultInfo : $this->errors;
  3790.     }
  3791.  
  3792.     /**
  3793.      * Helper method to see if an execution id exists on DB
  3794.      * no checks regarding other data like test case , test plam, build, etc are done
  3795.      * 
  3796.      * 
  3797.      *     
  3798.      * @return boolean
  3799.      * @access protected
  3800.      */        
  3801.     protected function checkExecutionID($messagePrefix='',$setError=false)
  3802.     {
  3803.         // need to be implemented - franciscom
  3804.         $pname = self::$executionIDParamName;
  3805.         $status_ok = $this->_isParamPresent($pname,$messagePrefix,$setError);
  3806.         if(!$status_ok)
  3807.         {        
  3808.             $msg = $messagePrefix . sprintf(MISSING_REQUIRED_PARAMETER_STR, $pname);
  3809.             $this->errors[new IXR_Error(MISSING_REQUIRED_PARAMETER$msg);                      
  3810.         }
  3811.         else
  3812.         {
  3813.             $status_ok = is_int($this->args[$pname]&& $this->args[$pname0;
  3814.             if!$status_ok )
  3815.             {
  3816.                 $msg = $messagePrefix . sprintf(PARAMETER_NOT_INT_STR,$pname,$this->args[$pname]);
  3817.                 $this->errors[new IXR_Error(PARAMETER_NOT_INT$msg);
  3818.             }
  3819.             else
  3820.             {
  3821.                 
  3822.             }
  3823.         }
  3824.         return $status_ok;
  3825.     }
  3826.  
  3827.  
  3828.  
  3829.     /**
  3830.      * Helper method to see if the platform identity provided is valid 
  3831.      * This is the only method that should be called directly to check platform identity
  3832.      *     
  3833.      * If everything OK, platform id is setted.
  3834.      *
  3835.      * @param int $tplanID Test Plan ID
  3836.      * @param map $platformInfo key: platform ID
  3837.      * @param string $messagePrefix used to be prepended to error message
  3838.      *
  3839.      *
  3840.      * @return boolean
  3841.      * @access protected
  3842.      */    
  3843.     protected function checkPlatformIdentity($tplanID,$platformInfo=null,$messagePrefix='')
  3844.     {
  3845.         $status=true;
  3846.         $platformID=0;
  3847.         $myErrors=array();
  3848.  
  3849.         $name_exists = $this->_isParamPresent(self::$platformNameParamName,$messagePrefix);
  3850.         $id_exists $this->_isParamPresent(self::$platformIDParamName,$messagePrefix);
  3851.         $status $name_exists $id_exists;
  3852.         // for debug - file_put_contents('c:\checkPlatformIdentity.txt', $status ? 1:0);                            
  3853.  
  3854.         if(!$status)
  3855.         {
  3856.             $pname = self::$platformNameParamName . ' OR ' . self::$platformIDParamName; 
  3857.             $msg = $messagePrefix . sprintf(MISSING_REQUIRED_PARAMETER_STR, $pname);
  3858.             $this->errors[new IXR_Error(MISSING_REQUIRED_PARAMETER$msg);                      
  3859.         }        
  3860.         
  3861.         if($status)
  3862.         {
  3863.               // get test plan name is useful for error messages
  3864.                $tplanInfo = $this->tplanMgr->get_by_id($tplanID);
  3865.                if(is_null($platformInfo))
  3866.                {
  3867.                    $platformInfo = $this->tplanMgr->getPlatforms($tplanID,array('outputFormat' => 'map'));  
  3868.                }
  3869.  
  3870.             if(is_null($platformInfo))
  3871.             {
  3872.                 $status = false;
  3873.                    $msg = sprintf($messagePrefix . TESTPLAN_HAS_NO_PLATFORMS_STR,$tplanInfo['name']);
  3874.                    $this->errors[new IXR_Error(TESTPLAN_HAS_NO_PLATFORMS$msg);
  3875.             }
  3876.             
  3877.         }
  3878.          
  3879.         if( $status )
  3880.         {
  3881.             $platform_name = null;
  3882.             $platform_id = null;
  3883.             if($name_exists)
  3884.             { 
  3885.                 // file_put_contents('c:\checkPlatformIdentity.txt', $this->args[self::$platformNameParamName]);                            
  3886.                 // file_put_contents('c:\checkPlatformIdentity.txt', serialize($platformInfo));                            
  3887.                 // $this->errors[]=$platformInfo;
  3888.                 $platform_name = $this->args[self::$platformNameParamName];
  3889.                 $status in_array($this->args[self::$platformNameParamName],$platformInfo);
  3890.             }
  3891.             else
  3892.             {
  3893.                 $platform_id = $this->args[self::$platformIDParamName];
  3894.                 $status = isset($platformInfo[$this->args[self::$platformIDParamName]]);
  3895.             }
  3896.             
  3897.             if( !$status )
  3898.             {
  3899.                 // Platform does not exist in target testplan
  3900.                 // Can I Try to understand if platform exists on test project ?
  3901.                 // $this->tprojectMgr->                
  3902.                    $msg = sprintf($messagePrefix . PLATFORM_NOT_LINKED_TO_TESTPLAN_STR,
  3903.                                $platform_name,$platform_id,$tplanInfo['name']);
  3904.                    $this->errors[new IXR_Error(PLATFORM_NOT_LINKED_TO_TESTPLAN$msg);
  3905.             }    
  3906.         }
  3907.         
  3908.         if($status)
  3909.         {
  3910.             if($name_exists)
  3911.             { 
  3912.                     $dummy = array_flip($platformInfo);
  3913.                 $this->args[self::$platformIDParamName$dummy[$this->args[self::$platformNameParamName]];
  3914.             }
  3915.         }
  3916.         return $status;
  3917.     }   
  3918.  
  3919.  
  3920.  
  3921.    /**
  3922.      * update result of LASTE execution
  3923.      *
  3924.      * @param
  3925.      * @param struct $args
  3926.      * @param string $args["devKey"]
  3927.      * @param int $args["testplanid"]
  3928.      * @param int $args["platformid"]
  3929.      * @param int $args["buildid"]
  3930.      * @param int $args["testcaseid"] internal ID
  3931.      * @param string $args["status"]
  3932.      * @param string $args["notes"]
  3933.      *
  3934.      * @return mixed $resultInfo
  3935.      * 
  3936.      * @access protected
  3937.      */
  3938.  
  3939.     protected function _updateResult()
  3940.     {
  3941.         $platform_id = 0;
  3942.         $exec_id = 0;
  3943.         $build_id = $this->args[self::$buildIDParamName];
  3944.         $tester_id =  $this->userID;
  3945.         $status $this->args[self::$statusParamName];
  3946.         $testplan_id =    $this->args[self::$testPlanIDParamName];
  3947.         $tcversion_id =    $this->tcVersionID;
  3948.         $tcase_id $this->args[self::$testCaseIDParamName];
  3949.         $db_now=$this->dbObj->db_now();
  3950.     
  3951.         ifisset($this->args[self::$platformIDParamName]) )
  3952.         {
  3953.             $platform_id = $this->args[self::$platformIDParamName];     
  3954.         }
  3955.  
  3956.         // Here steps and expected results are not needed => do not request => less data on network
  3957.         $options = array('getSteps' => 0);
  3958.         $last_exec = $this->tcaseMgr->get_last_execution($tcase_id,testcase::ALL_VERSIONS,
  3959.                                                          $testplan_id,$build_id,$platform_id,$options);
  3960.         
  3961.         if!is_null($last_exec) )
  3962.         {
  3963.             $last_exec = current($last_exec);
  3964.             $execution_type = constant("TESTCASE_EXECUTION_TYPE_AUTO");
  3965.             $exec_id = $last_exec['execution_id'];
  3966.             $notes = '';
  3967.             $notes_update = '';
  3968.             
  3969.             if($this->_isNotePresent())
  3970.             {
  3971.                 $notes = $this->dbObj->prepare_string($this->args[self::$noteParamName]);
  3972.             }
  3973.             
  3974.             if(trim($notes) != "")
  3975.             {
  3976.                 $notes_update = ",notes='{$notes}'";  
  3977.             }
  3978.             
  3979.             $sql = " UPDATE {$this->tables['executions']} " .
  3980.                    " SET tester_id={$tester_id}, execution_ts={$db_now}," . 
  3981.                    " status='{$status}', execution_type= {$execution_type} " . 
  3982.                    " {$notes_update}  WHERE id = {$exec_id}";
  3983.             
  3984.             $this->dbObj->exec_query($sql);
  3985.         }
  3986.         return $exec_id;
  3987.     }    
  3988.  
  3989.    /**
  3990.      * Return a TestSuite by ID
  3991.      *
  3992.      * @param
  3993.      * @param struct $args
  3994.      * @param string $args["devKey"]
  3995.      * @param int $args["testsuiteid"]
  3996.      * @return mixed $resultInfo
  3997.      * 
  3998.      * @access public
  3999.      */
  4000.     public function getTestSuiteByID($args)
  4001.     { 
  4002.         $operation=__FUNCTION__;
  4003.         $msg_prefix="({$operation}) - ";
  4004.  
  4005.         $this->_setArgs($args);
  4006.         $status_ok=$this->_runChecks(array('authenticate','checkTestSuiteID'),$msg_prefix);
  4007.  
  4008.         $details='simple';
  4009.         $key2search=self::$detailsParamName;
  4010.         if$this->_isParamPresent($key2search) )
  4011.         { 
  4012.             $details=$this->args[$key2search];
  4013.         }
  4014.  
  4015.         if($status_ok && $this->userHasRight("mgt_view_tc"))
  4016.         { 
  4017.             $testSuiteID = $this->args[self::$testSuiteIDParamName];
  4018.             $tsuiteMgr new testsuite($this->dbObj);
  4019.             return $tsuiteMgr->get_by_id($testSuiteID);
  4020.  
  4021.         }
  4022.         else
  4023.         { 
  4024.             return $this->errors;
  4025.         }
  4026.     }
  4027.  
  4028.     /**
  4029.      * get list of TestSuites which are DIRECT children of a given TestSuite
  4030.      *
  4031.      * @param struct $args
  4032.      * @param string $args["devKey"]
  4033.      * @param int $args["testsuiteid"]
  4034.      * @return mixed $resultInfo
  4035.      *
  4036.      * @access public
  4037.      */
  4038.     public function getTestSuitesForTestSuite($args)
  4039.     {
  4040.         $operation=__FUNCTION__;
  4041.         $msg_prefix="({$operation}) - ";
  4042.         $items = null;
  4043.     
  4044.         $this->_setArgs($args);
  4045.         $status_ok $this->_runChecks(array('authenticate','checkTestSuiteID'),$msg_prefix&& 
  4046.                      $this->userHasRight("mgt_view_tc");
  4047.         if$status_ok )
  4048.         {
  4049.             $testSuiteID = $this->args[self::$testSuiteIDParamName];
  4050.             $tsuiteMgr new testsuite($this->dbObj);
  4051.             $items $tsuiteMgr->get_children($testSuiteID);
  4052.         }
  4053.         return $status_ok ? $items : $this->errors;
  4054.     }
  4055.  
  4056.  
  4057.     /**
  4058.      * Returns the list of platforms associated to a given test plan
  4059.      *
  4060.      * @param
  4061.      * @param struct $args
  4062.      * @param string $args["devKey"]
  4063.      * @param int $args["testplanid"]
  4064.      * @return mixed $resultInfo
  4065.      * 
  4066.      * @access public
  4067.      */
  4068.     public function getTestPlanPlatforms($args)
  4069.     {
  4070.         $operation=__FUNCTION__;
  4071.         $msg_prefix="({$operation}) - ";
  4072.         $this->_setArgs($args);    
  4073.         $status_ok false;
  4074.         $items null;
  4075.         
  4076.         // Checks if a test plan id was provided
  4077.         $status_ok $this->_isParamPresent(self::$testPlanIDParamName,$msg_prefix,self::SET_ERROR);
  4078.         
  4079.         if($status_ok)
  4080.         {
  4081.             // Checks if the provided test plan id is valid
  4082.             $status_ok=$this->_runChecks(array('authenticate','checkTestPlanID'),$msg_prefix);
  4083.         }
  4084.         if($status_ok)
  4085.         {
  4086.             $tplanID = $this->args[self::$testPlanIDParamName];
  4087.             // get test plan name is useful for error messages
  4088.             $tplanInfo $this->tplanMgr->get_by_id($tplanID);
  4089.             $items $this->tplanMgr->getPlatforms($tplanID);  
  4090.             if(($status_ok !is_null($items)) )
  4091.             {
  4092.                    $msg = sprintf($messagePrefix . TESTPLAN_HAS_NO_PLATFORMS_STR,$tplanInfo['name']);
  4093.                    $this->errors[new IXR_Error(TESTPLAN_HAS_NO_PLATFORMS$msg);
  4094.             }
  4095.         }
  4096.         return $status_ok ? $items : $this->errors;
  4097.     }   
  4098.  
  4099.     /**
  4100.      * Gets the summarized results grouped by platform.
  4101.      * @see testplan:getStatusTotalsByPlatform()
  4102.      *
  4103.      * @param struct $args
  4104.      * @param string $args["devKey"]
  4105.      * @param int $args["tplanid"] test plan id
  4106.      *
  4107.      * @return map where every element has:
  4108.      *
  4109.      *    'type' => 'platform'
  4110.      *    'total_tc => ZZ
  4111.      *    'details' => array ( 'passed' => array( 'qty' => X)
  4112.      *                         'failed' => array( 'qty' => Y)
  4113.      *                         'blocked' => array( 'qty' => U)
  4114.      *                       ....)
  4115.      *
  4116.      * @access public
  4117.      */
  4118.     public function getTotalsForTestPlan($args)
  4119.     {
  4120.         $operation=__FUNCTION__;
  4121.         $msg_prefix="({$operation}) - ";
  4122.         $total = null;
  4123.         
  4124.         $this->_setArgs($args);
  4125.         $status_ok=true;
  4126.  
  4127.         // Checks are done in order
  4128.         $checkFunctions array('authenticate','checkTestPlanID');
  4129.         $status_ok=$this->_runChecks($checkFunctions,$msg_prefix&& $this->userHasRight("mgt_view_tc");
  4130.  
  4131.         if$status_ok )
  4132.         {
  4133.             $total = $this->tplanMgr->getStatusTotalsByPlatform($this->args[self::$testPlanIDParamName]);
  4134.         }
  4135.  
  4136.         return $status_ok ? $total : $this->errors;
  4137.     }
  4138.  
  4139.  
  4140.  
  4141.     /**
  4142.      * @param struct $args
  4143.      * @param string $args["devKey"]
  4144.      * @param int $args["user"] user name
  4145.      *
  4146.      * @return true if everything OK, otherwise error structure
  4147.      *
  4148.      * @access public
  4149.      */
  4150.     public function doesUserExist($args)
  4151.     {
  4152.         $operation=__FUNCTION__;
  4153.          $msg_prefix="({$operation}) - ";
  4154.         $this->_setArgs($args);
  4155.             
  4156.         $user_id tlUser::doesUserExist($this->dbObj,$this->args[self::$userParamName]);                
  4157.         if!($status_ok !is_null($user_id)) )
  4158.         {
  4159.             $msg = $msg_prefix . sprintf(NO_USER_BY_THIS_LOGIN_STR,$this->args[self::$userParamName]);
  4160.             $this->errors[new IXR_Error(NO_USER_BY_THIS_LOGIN$msg);    
  4161.         }
  4162.         return $status_ok ? $status_ok : $this->errors;
  4163.     }
  4164.  
  4165.  
  4166.     /**
  4167.      * check if Developer Key exists.
  4168.      *
  4169.      * @param struct $args
  4170.      * @param string $args["devKey"]
  4171.      *
  4172.      * @return true if everything OK, otherwise error structure
  4173.      *
  4174.      * @access public
  4175.      */
  4176.     public function checkDevKey($args)
  4177.     {
  4178.         $operation=__FUNCTION__;
  4179.         $msg_prefix="({$operation}) - ";
  4180.         $this->_setArgs($args);
  4181.         $checkFunctions array('authenticate');
  4182.         $status_ok $this->_runChecks($checkFunctions,$msg_prefix);
  4183.         return $status_ok $status_ok $this->errors;        
  4184.     }
  4185.  
  4186.  
  4187. /**
  4188.  * Uploads an attachment for a Requirement Specification.
  4189.  * 
  4190.  * The attachment content must be Base64 encoded by the client before sending it.
  4191.  * 
  4192.  * @param struct $args
  4193.  * @param string $args["devKey"] Developer key
  4194.  * @param int $args["reqspecid"] The Requirement Specification ID
  4195.  * @param string $args["title"] (Optional) The title of the Attachment 
  4196.  * @param string $args["description"] (Optional) The description of the Attachment
  4197.  * @param string $args["filename"] The file name of the Attachment (e.g.:notes.txt)
  4198.  * @param string $args["filetype"] The file type of the Attachment (e.g.: text/plain)
  4199.  * @param string $args["content"] The content (Base64 encoded) of the Attachment
  4200.  * 
  4201.  * @since 1.9beta6
  4202.  * @return mixed $resultInfo an array containing the fk_id, fk_table, title, 
  4203.  * description, file_name, file_size and file_type. If any errors occur it 
  4204.  * returns the error map.
  4205.  */
  4206. public function uploadRequirementSpecificationAttachment($args)
  4207. {
  4208.     $msg_prefix = "(" .__FUNCTION__ . ") - ";
  4209.     $args[self::$foreignKeyTableNameParamName] = 'req_specs';
  4210.     $args[self::$foreignKeyIdParamName] = $args['reqspecid'];
  4211.     $this->_setArgs($args);
  4212.     return $this->uploadAttachment($args,$msg_prefix,false);
  4213. }
  4214.  
  4215. /**
  4216.  * Uploads an attachment for a Requirement.
  4217.  * 
  4218.  * The attachment content must be Base64 encoded by the client before sending it.
  4219.  * 
  4220.  * @param struct $args
  4221.  * @param string $args["devKey"] Developer key
  4222.  * @param int $args["requirementid"] The Requirement ID
  4223.  * @param string $args["title"] (Optional) The title of the Attachment 
  4224.  * @param string $args["description"] (Optional) The description of the Attachment
  4225.  * @param string $args["filename"] The file name of the Attachment (e.g.:notes.txt)
  4226.  * @param string $args["filetype"] The file type of the Attachment (e.g.: text/plain)
  4227.  * @param string $args["content"] The content (Base64 encoded) of the Attachment
  4228.  * 
  4229.  * @since 1.9beta6
  4230.  * @return mixed $resultInfo an array containing the fk_id, fk_table, title, 
  4231.  * description, file_name, file_size and file_type. If any errors occur it 
  4232.  * returns the erros map.
  4233.  */
  4234. public function uploadRequirementAttachment($args)
  4235. {
  4236.     $msg_prefix = "(" .__FUNCTION__ . ") - ";
  4237.     $args[self::$foreignKeyTableNameParamName] = 'requirements';
  4238.     $args[self::$foreignKeyIdParamName] = $args['requirementid'];
  4239.     $this->_setArgs($args);
  4240.     return $this->uploadAttachment($args,$msg_prefix,false);
  4241. }
  4242.  
  4243. /**
  4244.  * Uploads an attachment for a Test Project.
  4245.  * 
  4246.  * The attachment content must be Base64 encoded by the client before sending it.
  4247.  * 
  4248.  * @param struct $args
  4249.  * @param string $args["devKey"] Developer key
  4250.  * @param int $args["testprojectid"] The Test Project ID
  4251.  * @param string $args["title"] (Optional) The title of the Attachment 
  4252.  * @param string $args["description"] (Optional) The description of the Attachment
  4253.  * @param string $args["filename"] The file name of the Attachment (e.g.:notes.txt)
  4254.  * @param string $args["filetype"] The file type of the Attachment (e.g.: text/plain)
  4255.  * @param string $args["content"] The content (Base64 encoded) of the Attachment
  4256.  * 
  4257.  * @since 1.9beta6
  4258.  * @return mixed $resultInfo an array containing the fk_id, fk_table, title, 
  4259.  * description, file_name, file_size and file_type. If any errors occur it 
  4260.  * returns the erros map.
  4261.  */
  4262. public function uploadTestProjectAttachment($args)
  4263. {
  4264.     $msg_prefix = "(" .__FUNCTION__ . ") - ";
  4265.     $ret = null;
  4266.     
  4267.     $args[self::$foreignKeyTableNameParamName] = 'nodes_hierarchy';
  4268.     $args[self::$foreignKeyIdParamName] = $args[self::$testProjectIDParamName];
  4269.     $this->_setArgs($args);
  4270.     
  4271.     $checkFunctions array('authenticate''checkTestProjectID');
  4272.     $statusOk $this->_runChecks($checkFunctions&& $this->userHasRight("mgt_view_tc");
  4273.     $ret $statusOk $this->uploadAttachment($args,$msg_prefix,false$this->errors;
  4274.     return $ret;
  4275. }
  4276.  
  4277. /**
  4278.  * Uploads an attachment for a Test Suite.
  4279.  * 
  4280.  * The attachment content must be Base64 encoded by the client before sending it.
  4281.  * 
  4282.  * @param struct $args
  4283.  * @param string $args["devKey"] Developer key
  4284.  * @param int $args["testsuiteid"] The Test Suite ID
  4285.  * @param string $args["title"] (Optional) The title of the Attachment 
  4286.  * @param string $args["description"] (Optional) The description of the Attachment
  4287.  * @param string $args["filename"] The file name of the Attachment (e.g.:notes.txt)
  4288.  * @param string $args["filetype"] The file type of the Attachment (e.g.: text/plain)
  4289.  * @param string $args["content"] The content (Base64 encoded) of the Attachment
  4290.  * 
  4291.  * @since 1.9beta6
  4292.  * @return mixed $resultInfo an array containing the fk_id, fk_table, title, 
  4293.  * description, file_name, file_size and file_type. If any errors occur it 
  4294.  * returns the erros map.
  4295.  */
  4296. public function uploadTestSuiteAttachment($args)
  4297. {
  4298.     $msg_prefix = "(" .__FUNCTION__ . ") - ";
  4299.     $args[self::$foreignKeyTableNameParamName] = 'nodes_hierarchy';
  4300.     $args[self::$foreignKeyIdParamName] = $args[self::$testSuiteIDParamName];
  4301.     $this->_setArgs($args);
  4302.     
  4303.     $checkFunctions array('authenticate''checkTestSuiteID');
  4304.     $statusOk $this->_runChecks($checkFunctions&& $this->userHasRight("mgt_view_tc");
  4305.     $ret $statusOk $this->uploadAttachment($args,$msg_prefix,false$this->errors;
  4306.     return $ret;
  4307. }
  4308.  
  4309. /**
  4310.  * Uploads an attachment for a Test Case.
  4311.  * 
  4312.  * The attachment content must be Base64 encoded by the client before sending it.
  4313.  * 
  4314.  * @param struct $args
  4315.  * @param string $args["devKey"] Developer key
  4316.  * @param int $args["testcaseid"] Test Case INTERNAL ID
  4317.  * @param string $args["title"] (Optional) The title of the Attachment 
  4318.  * @param string $args["description"] (Optional) The description of the Attachment
  4319.  * @param string $args["filename"] The file name of the Attachment (e.g.:notes.txt)
  4320.  * @param string $args["filetype"] The file type of the Attachment (e.g.: text/plain)
  4321.  * @param string $args["content"] The content (Base64 encoded) of the Attachment
  4322.  * 
  4323.  * @since 1.9beta6
  4324.  * @return mixed $resultInfo an array containing the fk_id, fk_table, title, 
  4325.  * description, file_name, file_size and file_type. If any errors occur it 
  4326.  * returns the erros map.
  4327.  */
  4328. public function uploadTestCaseAttachment($args)
  4329. {
  4330.     $ret = null;
  4331.     $msg_prefix = "(" .__FUNCTION__ . ") - ";
  4332.     
  4333.     $args[self::$foreignKeyTableNameParamName] = 'nodes_hierarchy';
  4334.     $args[self::$foreignKeyIdParamName] = $args[self::$testCaseIDParamName];
  4335.     $this->_setArgs($args);
  4336.     $checkFunctions array('authenticate''checkTestCaseID');
  4337.  
  4338.     $statusOk $this->_runChecks($checkFunctions,$msg_prefix&& $this->userHasRight("mgt_view_tc");
  4339.     $ret $statusOk $this->uploadAttachment($args,$msg_prefix,false$this->errors;
  4340.     return $ret;
  4341. }
  4342.  
  4343. /**
  4344.  * Uploads an attachment for an execution.
  4345.  * 
  4346.  * The attachment content must be Base64 encoded by the client before sending it.
  4347.  * 
  4348.  * @param struct $args
  4349.  * @param string $args["devKey"] Developer key
  4350.  * @param int $args["executionid"] execution ID
  4351.  * @param string $args["title"] (Optional) The title of the Attachment 
  4352.  * @param string $args["description"] (Optional) The description of the Attachment
  4353.  * @param string $args["filename"] The file name of the Attachment (e.g.:notes.txt)
  4354.  * @param string $args["filetype"] The file type of the Attachment (e.g.: text/plain)
  4355.  * @param string $args["content"] The content (Base64 encoded) of the Attachment
  4356.  * 
  4357.  * @since 1.9beta6
  4358.  * @return mixed $resultInfo an array containing the fk_id, fk_table, title, 
  4359.  * description, file_name, file_size and file_type. If any errors occur it 
  4360.  * returns the erros map.
  4361.  */
  4362. public function uploadExecutionAttachment($args)
  4363. {
  4364.     $msg_prefix = "(" .__FUNCTION__ . ") - ";
  4365.     $args[self::$foreignKeyTableNameParamName] = 'executions';
  4366.     $args[self::$foreignKeyIdParamName] = $args['executionid'];
  4367.     $this->_setArgs($args);
  4368.     return $this->uploadAttachment($args,$msg_prefix,false);
  4369. }
  4370.  
  4371. /**
  4372.  * Uploads an attachment for specified table. You must specify the table that 
  4373.  * the attachment is connected (nodes_hierarchy, builds, etc) and the foreign 
  4374.  * key id in this table.
  4375.  * 
  4376.  * The attachment content must be Base64 encoded by the client before sending it.
  4377.  * 
  4378.  * @param struct $args
  4379.  * @param string $args["devKey"] Developer key
  4380.  * @param int $args["fkid"] The Attachment Foreign Key ID
  4381.  * @param string $args["fktable"] The Attachment Foreign Key Table
  4382.  * @param string $args["title"] (Optional) The title of the Attachment 
  4383.  * @param string $args["description"] (Optional) The description of the Attachment
  4384.  * @param string $args["filename"] The file name of the Attachment (e.g.:notes.txt)
  4385.  * @param string $args["filetype"] The file type of the Attachment (e.g.: text/plain)
  4386.  * @param string $args["content"] The content (Base64 encoded) of the Attachment
  4387.  * 
  4388.  * @since 1.9beta6
  4389.  * @return mixed $resultInfo an array containing the fk_id, fk_table, title, 
  4390.  * description, file_name, file_size and file_type. If any errors occur it 
  4391.  * returns the erros map.
  4392.  */
  4393. public function uploadAttachment($args, $messagePrefix='', $setArgs=true)
  4394. {
  4395.     $resultInfo = array();
  4396.     if( $setArgs )
  4397.     {
  4398.         $this->_setArgs($args);
  4399.     }
  4400.     $msg_prefix = ($messagePrefix == '') ? ("(" .__FUNCTION__ . ") - ") : $messagePrefix;
  4401.     
  4402.     $checkFunctions = array();
  4403.     
  4404.     // TODO: please, somebody review if this is valid. I added this property 
  4405.     // to avoid the upload method of double authenticating the user. 
  4406.     // Otherwise, when uploadTestCaseAttachment was called, for instante, it 
  4407.     // would authenticate, check if the nodes_hierarchy is type TestCase 
  4408.     // and then call uploadAttachment that would, authenticate again.
  4409.     // What do you think?
  4410.     if( !$this->authenticated 
  4411.     {
  4412.         $checkFunctions[] = 'authenticate'; 
  4413.     }
  4414.     // check if :
  4415.     // TL has attachments enabled
  4416.     // provided FK is valid
  4417.     // attachment info is ok
  4418.     $checkFunctions[] = 'isAttachmentEnabled'; 
  4419.     $checkFunctions[] = 'checkForeignKey';
  4420.     $checkFunctions[] = 'checkUploadAttachmentRequest';
  4421.  
  4422.     $statusOk = $this->_runChecks($checkFunctions,$msg_prefix)// && $this->userHasRight("mgt_view_tc");
  4423.  
  4424.     if($statusOk)
  4425.     {        
  4426.         $fkId = $this->args[self::$foreignKeyIdParamName];
  4427.         $fkTable $this->args[self::$foreignKeyTableNameParamName];
  4428.         $title $this->args[self::$titleParamName];
  4429.  
  4430.         // return array($fkId,$fkTable,$title);        
  4431.         // creates a temp file and returns an array with size and tmp_name
  4432.         $fInfo $this->createAttachmentTempFile();
  4433.         if !$fInfo )
  4434.         {
  4435.             // Error creating attachment temp file. Ask user to check temp dir 
  4436.             // settings in php.ini and security and rights of this dir.
  4437.             $msg = $msg_prefix . ATTACH_TEMP_FILE_CREATION_ERROR_STR;
  4438.             $this->errors[new IXR_ERROR(ATTACH_TEMP_FILE_CREATION_ERROR,$msg)
  4439.             $statusOk false;
  4440.         } 
  4441.         else 
  4442.         {
  4443.             // The values have already been validated in the method 
  4444.             // checkUploadAttachmentRequest()
  4445.             $fInfo['name'] = $args[self::$fileNameParamName];
  4446.             $fInfo['type'] = $args[self::$fileTypeParamName];
  4447.             
  4448.             $attachmentRepository = tlAttachmentRepository::create($this->dbObj);
  4449.             $uploadedFile $attachmentRepository->insertAttachment($fkId,$fkTable,$title,$fInfo);
  4450.             if!$uploadedFile )
  4451.             {
  4452.                 $msg = $msg_prefix . ATTACH_DB_WRITE_ERROR_STR;
  4453.                 $this->errors[new IXR_ERROR(ATTACH_DB_WRITE_ERROR,$msg)
  4454.                 $statusOk false
  4455.             } 
  4456.             else 
  4457.             {
  4458.                 // We are returning some data that the user originally sent. 
  4459.                 // Perhaps we could return only new data, like the file size?
  4460.                 $resultInfo['fk_id'] = $args[self::$foreignKeyIdParamName];
  4461.                 $resultInfo['fk_table'] = $args[self::$foreignKeyTableNameParamName];
  4462.                 $resultInfo['title'] = $args[self::$titleParamName];
  4463.                 $resultInfo['description'] = $args[self::$descriptionParamName];
  4464.                 $resultInfo['file_name'] = $args[self::$fileNameParamName];
  4465.  
  4466.                 // It would be nice have all info available in db
  4467.                 // $resultInfo['file_path'] = $args[""]; 
  4468.                 // we could also return the tmp_name, but would it be useful?
  4469.                  $resultInfo['file_size'] = $fInfo['size'];
  4470.                  $resultInfo['file_type'] = $args[self::$fileTypeParamName];
  4471.             }
  4472.         }
  4473.     }
  4474.       
  4475.     return $statusOk ? $resultInfo : $this->errors;
  4476. }
  4477.  
  4478. /**
  4479.  * <p>Checks if the attachments feature is enabled in TestLink 
  4480.  * configuration.</p>
  4481.  * 
  4482.  * @since 1.9beta6
  4483.  * @return boolean true if attachments feature is enabled in TestLink 
  4484.  * configuration, false otherwise.
  4485.  */
  4486. protected function isAttachmentEnabled($msg_prefix='')
  4487. {
  4488.     $status_ok = true;
  4489.     if (!config_get("attachments")->enabled
  4490.     {
  4491.         $msg = $msg_prefix . ATTACH_FEATURE_DISABLED_STR;
  4492.         $this->errors[new IXR_ERROR(ATTACH_FEATURE_DISABLED,$msg)
  4493.         $status_ok false;
  4494.     }
  4495.     return $status_ok;
  4496. }
  4497.  
  4498. /**
  4499.  * <p>Checks if the given foreign key is valid. What this method basically does 
  4500.  * is query the database looking for the foreign key id in the foreign key 
  4501.  * table.</p>
  4502.  * 
  4503.  * @since 1.9beta6
  4504.  * @return boolean true if the given foreign key exists, false otherwise.
  4505.  */
  4506. protected function checkForeignKey($msg_prefix='')
  4507. {
  4508.     $statusOk = true;
  4509.     
  4510.     $fkId = $this->args[self::$foreignKeyIdParamName];
  4511.     $fkTable $this->args[self::$foreignKeyTableNameParamName];
  4512.     
  4513.     if isset($fkId&& isset($fkTable) )
  4514.     {
  4515.         $query = "SELECT id FROM {$this->tables[$fkTable]} WHERE id={$fkId}";
  4516.         $result = $this->dbObj->fetchFirstRowSingleColumn($query"id");
  4517.     }
  4518.            
  4519.     if(null == $result)
  4520.     {
  4521.         $msg = $msg_prefix . sprintf(ATTACH_INVALID_FK_STR, $fkId, $fkTable);
  4522.         $this->errors[new IXR_ERROR(ATTACH_INVALID_FK,$msg);
  4523.         $statusOk false;             
  4524.     }
  4525.     
  4526.     return $statusOk;
  4527. }
  4528.  
  4529. /**
  4530.  * <p>Checks if the attachment parameters are valid. It checks if the 
  4531.  * <b>file_name</b> parameter is set, if the <b>content</b> is set and if 
  4532.  * the <b>file type</b> is set. If the <b>file type</b> is not set, then it uses 
  4533.  * <b>application/octet-stream</b>. 
  4534.  * This default content type refers to <i>binary</i> files.</p> 
  4535.  * 
  4536.  * @since 1.9beta6
  4537.  * @return boolean true if the file name and the content are set
  4538.  */
  4539. protected function checkUploadAttachmentRequest($msg_prefix = '')
  4540. {
  4541.     // Did the client set file name?
  4542.     $status = isset($this->args[self::$fileNameParamName]);
  4543.     if $status )
  4544.     {
  4545.         // Did the client set file content? 
  4546.         $status = isset($this->args[self::$contentParamName]);
  4547.         if $status )
  4548.         {
  4549.             // Did the client set the file type? If not so use binary as default file type
  4550.             if ( isset($this->args[self::$fileTypeParamName]) )
  4551.             {
  4552.                 // By default, if no file type is provided, put it as binary
  4553.                 $this->args[self::$fileTypeParamName"application/octet-stream";
  4554.             }
  4555.         }
  4556.     }
  4557.  
  4558.     if(!$status) 
  4559.     {
  4560.         $msg = $msg_prefix . sprintf(ATTACH_INVALID_ATTACHMENT_STR, $this->args[self::$fileNameParamName]
  4561.                                      sizeof($this->args[self::$contentParamName]));
  4562.         $this->errors[new IXR_ERROR(ATTACH_INVALID_ATTACHMENT,$msg);
  4563.     }
  4564.     
  4565.     return $status;
  4566. }
  4567.  
  4568. /**
  4569.  * <p>Creates a temporary file and writes the attachment content into this file.</p>
  4570.  * 
  4571.  * <p>Before writing to the file it <b>Base64 decodes</b> the file content.</p>
  4572.  * 
  4573.  * @since 1.9beta6
  4574.  * @return file handler
  4575.  */
  4576. protected function createAttachmentTempFile()
  4577. {
  4578.     $resultInfo = array();
  4579.     $filename = tempnam(sys_get_temp_dir(), 'tl-');
  4580.     
  4581.     $resultInfo["tmp_name"] = $filename;
  4582.     $handle = fopen( $filename, "w" );
  4583.     fwrite($handle, base64_decode($this->args[self::$contentParamName]));
  4584.     fclose$handle );
  4585.     
  4586.     $filesize filesize($filename);
  4587.     $resultInfo["size"$filesize;
  4588.     
  4589.     return $resultInfo;
  4590. }
  4591.  
  4592.  
  4593.  
  4594.     /**
  4595.      * checks if a test case version number is defined for a test case
  4596.      *
  4597.      * @param string $messagePrefix used to be prepended to error message
  4598.      * 
  4599.      * @return map with following keys
  4600.      *             boolean map['status_ok']
  4601.      *             string map['error_msg']
  4602.      *             int map['error_code']
  4603.      */
  4604.     protected function checkTestCaseVersionNumberAncestry($messagePrefix='')
  4605.     {
  4606.         $ret=array('status_ok' => true, 'error_msg' => '' , 'error_code' => 0);
  4607.     
  4608.         $tcase_id = $this->args[self::$testCaseIDParamName];
  4609.         $version_number $this->args[self::$versionNumberParamName];
  4610.         
  4611.         $sql " SELECT TCV.version,TCV.id " 
  4612.                " FROM {$this->tables['nodes_hierarchy']} NH, {$this->tables['tcversions']} TCV " .
  4613.                " WHERE NH.parent_id = {$tcase_id} " .
  4614.                " AND TCV.version = {$version_number} " .
  4615.                " AND TCV.id = NH.id ";
  4616.     
  4617.         $target_tcversion = $this->dbObj->fetchRowsIntoMap($sql,'version');
  4618.         // $xx = "tcase_id:$tcase_id - version_number:$version_number";
  4619.         // file_put_contents('c:\checkTestCaseVersionNumberAncestry.php.xmlrpc', $xx);                            
  4620.         
  4621.         if!is_null($target_tcversion&& count($target_tcversion== )
  4622.         {
  4623.             $dummy = current($target_tcversion);
  4624.             $this->tcVersionID = $dummy['id'];
  4625.         }
  4626.         else
  4627.         {
  4628.             $status_ok=false;
  4629.             $tcase_info = $this->tcaseMgr->tree_manager->get_node_hierarchy_info($tcase_id);
  4630.             $msg sprintf(TCASE_VERSION_NUMBER_KO_STR,$version_number,$this->args[self::$testCaseExternalIDParamName],
  4631.                            $tcase_info['name']);  
  4632.             $ret array('status_ok' => false'error_msg' => $msg 'error_code' => TCASE_VERSION_NUMBER_KO);                                               
  4633.         }  
  4634.                         
  4635.         // $xx = "this->tcVersionID:$this->tcVersionID";
  4636.         // file_put_contents('c:\checkTestCaseVersionNumberAncestry.php.xmlrpc', $xx,FILE_APPEND); 
  4637.         return $ret;
  4638.     } // function end
  4639. } // class end

Documentation generated on Fri, 17 Feb 2012 16:07:49 -0500 by phpDocumentor 1.4.4