protected function execute(ConduitAPIRequest $request)
 {
     $viewer = $request->getUser();
     $build_target_phid = $request->getValue('buildTargetPHID');
     $build_target = id(new HarbormasterBuildTargetQuery())->setViewer($viewer)->withPHIDs(array($build_target_phid))->executeOne();
     if (!$build_target) {
         throw new Exception(pht('No such build target "%s"!', $build_target_phid));
     }
     $artifact_type = $request->getValue('artifactType');
     // Cast "artifactData" parameters to acceptable types if this request
     // is submitting raw HTTP parameters. This is not ideal. See T11887 for
     // discussion.
     $artifact_data = $request->getValue('artifactData');
     if (!$request->getIsStrictlyTyped()) {
         $impl = HarbormasterArtifact::getArtifactType($artifact_type);
         if ($impl) {
             foreach ($artifact_data as $key => $value) {
                 $artifact_data[$key] = $impl->readArtifactHTTPParameter($key, $value);
             }
         }
     }
     $artifact = $build_target->createArtifact($viewer, $request->getValue('artifactKey'), $artifact_type, $artifact_data);
     return array('data' => $this->returnArtifactList(array($artifact)));
 }
 public function buildConduitResponse(ConduitAPIRequest $request, ConduitAPIMethod $method)
 {
     $viewer = $this->requireViewer();
     $query_key = $request->getValue('queryKey');
     if (!strlen($query_key)) {
         $saved_query = new PhabricatorSavedQuery();
     } else {
         if ($this->isBuiltinQuery($query_key)) {
             $saved_query = $this->buildSavedQueryFromBuiltin($query_key);
         } else {
             $saved_query = id(new PhabricatorSavedQueryQuery())->setViewer($viewer)->withQueryKeys(array($query_key))->executeOne();
             if (!$saved_query) {
                 throw new Exception(pht('Query key "%s" does not correspond to a valid query.', $query_key));
             }
         }
     }
     $constraints = $request->getValue('constraints', array());
     $fields = $this->getSearchFieldsForConduit();
     foreach ($fields as $key => $field) {
         if (!$field->getConduitParameterType()) {
             unset($fields[$key]);
         }
     }
     $valid_constraints = array();
     foreach ($fields as $field) {
         foreach ($field->getValidConstraintKeys() as $key) {
             $valid_constraints[$key] = true;
         }
     }
     foreach ($constraints as $key => $constraint) {
         if (empty($valid_constraints[$key])) {
             throw new Exception(pht('Constraint "%s" is not a valid constraint for this query.', $key));
         }
     }
     foreach ($fields as $field) {
         if (!$field->getValueExistsInConduitRequest($constraints)) {
             continue;
         }
         $value = $field->readValueFromConduitRequest($constraints, $request->getIsStrictlyTyped());
         $saved_query->setParameter($field->getKey(), $value);
     }
     // NOTE: Currently, when running an ad-hoc query we never persist it into
     // a saved query. We might want to add an option to do this in the future
     // (for example, to enable a CLI-to-Web workflow where user can view more
     // details about results by following a link), but have no use cases for
     // it today. If we do identify a use case, we could save the query here.
     $query = $this->buildQueryFromSavedQuery($saved_query);
     $pager = $this->newPagerForSavedQuery($saved_query);
     $attachments = $this->getConduitSearchAttachments();
     // TODO: Validate this better.
     $attachment_specs = $request->getValue('attachments', array());
     $attachments = array_select_keys($attachments, array_keys($attachment_specs));
     foreach ($attachments as $key => $attachment) {
         $attachment->setViewer($viewer);
     }
     foreach ($attachments as $key => $attachment) {
         $attachment->willLoadAttachmentData($query, $attachment_specs[$key]);
     }
     $this->setQueryOrderForConduit($query, $request);
     $this->setPagerLimitForConduit($pager, $request);
     $this->setPagerOffsetsForConduit($pager, $request);
     $objects = $this->executeQuery($query, $pager);
     $data = array();
     if ($objects) {
         $field_extensions = $this->getConduitFieldExtensions();
         $extension_data = array();
         foreach ($field_extensions as $key => $extension) {
             $extension_data[$key] = $extension->loadExtensionConduitData($objects);
         }
         $attachment_data = array();
         foreach ($attachments as $key => $attachment) {
             $attachment_data[$key] = $attachment->loadAttachmentData($objects, $attachment_specs[$key]);
         }
         foreach ($objects as $object) {
             $field_map = $this->getObjectWireFieldsForConduit($object, $field_extensions, $extension_data);
             $attachment_map = array();
             foreach ($attachments as $key => $attachment) {
                 $attachment_map[$key] = $attachment->getAttachmentForObject($object, $attachment_data[$key], $attachment_specs[$key]);
             }
             // If this is empty, we still want to emit a JSON object, not a
             // JSON list.
             if (!$attachment_map) {
                 $attachment_map = (object) $attachment_map;
             }
             $id = (int) $object->getID();
             $phid = $object->getPHID();
             $data[] = array('id' => $id, 'type' => phid_get_type($phid), 'phid' => $phid, 'fields' => $field_map, 'attachments' => $attachment_map);
         }
     }
     return array('data' => $data, 'maps' => $method->getQueryMaps($query), 'query' => array('queryKey' => $saved_query->getQueryKey()), 'cursor' => array('limit' => $pager->getPageSize(), 'after' => $pager->getNextPageID(), 'before' => $pager->getPrevPageID(), 'order' => $request->getValue('order')));
 }
 /**
  * Generate transactions which can be applied from edit actions in a Conduit
  * request.
  *
  * @param ConduitAPIRequest The request.
  * @param list<PhabricatorEditType> Supported edit types.
  * @param PhabricatorApplicationTransaction Template transaction.
  * @return list<PhabricatorApplicationTransaction> Generated transactions.
  * @task conduit
  */
 private function getConduitTransactions(ConduitAPIRequest $request, array $types, PhabricatorApplicationTransaction $template)
 {
     $viewer = $request->getUser();
     $transactions_key = 'transactions';
     $xactions = $request->getValue($transactions_key);
     if (!is_array($xactions)) {
         throw new Exception(pht('Parameter "%s" is not a list of transactions.', $transactions_key));
     }
     foreach ($xactions as $key => $xaction) {
         if (!is_array($xaction)) {
             throw new Exception(pht('Parameter "%s" must contain a list of transaction descriptions, ' . 'but item with key "%s" is not a dictionary.', $transactions_key, $key));
         }
         if (!array_key_exists('type', $xaction)) {
             throw new Exception(pht('Parameter "%s" must contain a list of transaction descriptions, ' . 'but item with key "%s" is missing a "type" field. Each ' . 'transaction must have a type field.', $transactions_key, $key));
         }
         $type = $xaction['type'];
         if (empty($types[$type])) {
             throw new Exception(pht('Transaction with key "%s" has invalid type "%s". This type is ' . 'not recognized. Valid types are: %s.', $key, $type, implode(', ', array_keys($types))));
         }
     }
     $results = array();
     if ($this->getIsCreate()) {
         $results[] = id(clone $template)->setTransactionType(PhabricatorTransactions::TYPE_CREATE);
     }
     foreach ($xactions as $xaction) {
         $type = $types[$xaction['type']];
         // Let the parameter type interpret the value. This allows you to
         // use usernames in list<user> fields, for example.
         $parameter_type = $type->getConduitParameterType();
         $parameter_type->setViewer($viewer);
         try {
             $xaction['value'] = $parameter_type->getValue($xaction, 'value', $request->getIsStrictlyTyped());
         } catch (Exception $ex) {
             throw new PhutilProxyException(pht('Exception when processing transaction of type "%s": %s', $xaction['type'], $ex->getMessage()), $ex);
         }
         $type_xactions = $type->generateTransactions(clone $template, $xaction);
         foreach ($type_xactions as $type_xaction) {
             $results[] = $type_xaction;
         }
     }
     return $results;
 }