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; }