/** * Runs a rappture job. * * This is more than just invoking a tool. We're expecting a driver file to pass to the * tool to be picked up and automatically run by rappture. * * @apiMethod POST * @apiUri /tools/run * @apiParameter { * "name": "app", * "description": "Name of app installed as a tool in the hub", * "type": "string", * "required": true, * } * @apiParameter { * "name": "revision", * "description": "The specific requested revision of the app", * "type": "string", * "required": false, * "default": "default", * } * @apiParameter { * "name": "xml", * "description": "Content of the driver file that rappture will use to invoke the given app", * "type": "string", * "required": true, * } * @return void */ public function runTask() { $this->requiresAuthentication(); // Get the user_id and attempt to load user profile $userid = App::get('authn')['user_id']; $profile = User::getInstance($userid); // Make sure we have a user if (!$profile->get('id')) { throw new Exception(Lang::txt('Unable to find user.'), 404); } // Grab tool name and version $tool_name = Request::getVar('app', ''); $tool_version = Request::getVar('revision', 'default'); // Build application object $app = new stdClass(); $app->name = trim(str_replace(':', '-', $tool_name)); $app->version = $tool_version; $app->ip = $_SERVER["REMOTE_ADDR"]; // Check to make sure we have an app to invoke if (!$app->name) { throw new Exception(Lang::txt('A valid app name must be provided'), 404); } // Include needed tool libraries require_once dirname(dirname(__DIR__)) . DS . 'tables' . DS . 'version.php'; require_once dirname(dirname(__DIR__)) . DS . 'tables' . DS . 'session.php'; require_once dirname(dirname(__DIR__)) . DS . 'tables' . DS . 'viewperm.php'; // Create database object $database = \App::get('db'); // Load the tool version $tv = new \Components\Tools\Tables\Version($database); switch ($app->version) { case 1: case 'default': $app->name = $tv->getCurrentVersionProperty($app->name, 'instance'); break; case 'test': case 'dev': $app->name .= '_dev'; break; default: $app->name .= '_r' . $app->version; break; } $app->toolname = $app->name; if ($parent = $tv->getToolname($app->name)) { $app->toolname = $parent; } // Check of the toolname has a revision indicator $r = substr(strrchr($app->name, '_'), 1); if (substr($r, 0, 1) != 'r' && substr($r, 0, 3) != 'dev') { $r = ''; } // No version passed and no revision if ((!$app->version || $app->version == 'default') && !$r) { // Get the latest version $app->version = $tv->getCurrentVersionProperty($app->toolname, 'revision'); $app->name = $app->toolname . '_r' . $app->version; } // Get the caption/session title $tv->loadFromInstance($app->name); $app->caption = stripslashes($tv->title); $app->title = stripslashes($tv->title); // Make sure we have a valid tool if ($app->title == '' || $app->toolname == '') { throw new Exception(Lang::txt('The tool "%s" does not exist on the HUB.', $tool_name), 404); } // Get tool access $toolAccess = \Components\Tools\Helpers\Utils::getToolAccess($app->name, $profile->get('username')); // Do we have access if ($toolAccess->valid != 1) { throw new Exception($toolAccess->error->message, 500); } // Log the launch attempt \Components\Tools\Helpers\Utils::recordToolUsage($app->toolname, $profile->get('id')); // Get the middleware database $mwdb = \Components\Tools\Helpers\Utils::getMWDBO(); // Find out how many sessions the user is running $ms = new \Components\Tools\Tables\Session($mwdb); $jobs = $ms->getCount($profile->get('username')); // Find out how many sessions the user is ALLOWED to run. include_once dirname(dirname(__DIR__)) . DS . 'tables' . DS . 'preferences.php'; $preferences = new \Components\Tools\Tables\Preferences($database); $preferences->loadByUser($profile->get('id')); if (!$preferences || !$preferences->id) { $default = $preferences->find('one', array('alias' => 'default')); $preferences->user_id = $profile->get('id'); $preferences->class_id = $default->id; $preferences->jobs = $default->jobs; $preferences->store(); } $remain = $preferences->jobs - $jobs; //can we open another session if ($remain <= 0) { throw new Exception(Lang::txt('You are using all (%s) your available job slots.', $jobs), 401); } // Check for an incoming driver file if ($driver = Request::getVar('xml', false, 'post', 'none', 2)) { // Build a path to where the driver file will go through webdav $base = DS . 'webdav' . DS . 'home'; $user = DS . $profile->get('username'); $data = DS . 'data'; $drvr = DS . '.queued_drivers'; $inst = DS . md5(time()) . '.xml'; // Real home directory $homeDir = $profile->get('homeDirectory'); // First, make sure webdav is there and that the necessary folders are there if (!\Filesystem::exists($base)) { throw new Exception(Lang::txt('Home directories are unavailable'), 500); } // Now see if the user has a home directory yet if (!\Filesystem::exists($homeDir)) { // Try to create their home directory require_once dirname(dirname(__DIR__)) . DS . 'helpers' . DS . 'utils.php'; if (!\Components\Tools\Helpers\Utils::createHomeDirectory($profile->get('username'))) { throw new Exception(Lang::txt('Failed to create user home directory'), 500); } } // Check for, and create if needed a session data directory if (!\Filesystem::exists($base . $user . $data) && !\Filesystem::makeDirectory($base . $user . $data, 0700)) { throw new Exception(Lang::txt('Failed to create data directory'), 500); } // Check for, and create if needed a queued drivers directory if (!\Filesystem::exists($base . $user . $data . $drvr) && !\Filesystem::makeDirectory($base . $user . $data . $drvr, 0700)) { throw new Exception(Lang::txt('Failed to create drivers directory'), 500); } // Write the driver file out if (!\Filesystem::write($base . $user . $data . $drvr . $inst, $driver)) { throw new Exception(Lang::txt('Failed to create driver file'), 500); } } else { throw new Exception(Lang::txt('No driver file provided'), 404); } // Now build params path that will be included with tool execution // We know from the checks above that this directory already exists $params = 'file(execute):' . $homeDir . DS . 'data' . DS . '.queued_drivers' . $inst; $encoded = ' params=' . rawurlencode($params) . ' '; $command = 'start user='******'username') . " ip={$app->ip} app={$app->name} version={$app->version}" . $encoded; $status = \Components\Tools\Helpers\Utils::middleware($command, $output); if (!$status) { throw new Exception(Lang::txt('Tool invocation failed'), 500); } $this->send(array('success' => true, 'session' => $output->session)); }