Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14701930
D10777.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
28 KB
Referenced Files
None
Subscribers
None
D10777.diff
View Options
diff --git a/resources/sql/autopatches/20141103.almanac.1.delprop.sql b/resources/sql/autopatches/20141103.almanac.1.delprop.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20141103.almanac.1.delprop.sql
@@ -0,0 +1 @@
+DROP TABLE {$NAMESPACE}_almanac.almanac_deviceproperty;
diff --git a/resources/sql/autopatches/20141103.almanac.2.addprop.sql b/resources/sql/autopatches/20141103.almanac.2.addprop.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20141103.almanac.2.addprop.sql
@@ -0,0 +1,8 @@
+CREATE TABLE {$NAMESPACE}_almanac.almanac_property (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ objectPHID VARBINARY(64) NOT NULL,
+ fieldIndex BINARY(12) NOT NULL,
+ fieldName VARCHAR(128) NOT NULL COLLATE {$COLLATE_TEXT},
+ fieldValue LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
+ UNIQUE KEY `objectPHID` (objectPHID, fieldIndex)
+) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -22,9 +22,11 @@
'AlmanacConduitUtil' => 'applications/almanac/util/AlmanacConduitUtil.php',
'AlmanacConsoleController' => 'applications/almanac/controller/AlmanacConsoleController.php',
'AlmanacController' => 'applications/almanac/controller/AlmanacController.php',
+ 'AlmanacCoreCustomField' => 'applications/almanac/customfield/AlmanacCoreCustomField.php',
'AlmanacCreateDevicesCapability' => 'applications/almanac/capability/AlmanacCreateDevicesCapability.php',
'AlmanacCreateNetworksCapability' => 'applications/almanac/capability/AlmanacCreateNetworksCapability.php',
'AlmanacCreateServicesCapability' => 'applications/almanac/capability/AlmanacCreateServicesCapability.php',
+ 'AlmanacCustomField' => 'applications/almanac/customfield/AlmanacCustomField.php',
'AlmanacDAO' => 'applications/almanac/storage/AlmanacDAO.php',
'AlmanacDevice' => 'applications/almanac/storage/AlmanacDevice.php',
'AlmanacDeviceController' => 'applications/almanac/controller/AlmanacDeviceController.php',
@@ -32,7 +34,6 @@
'AlmanacDeviceEditor' => 'applications/almanac/editor/AlmanacDeviceEditor.php',
'AlmanacDeviceListController' => 'applications/almanac/controller/AlmanacDeviceListController.php',
'AlmanacDevicePHIDType' => 'applications/almanac/phid/AlmanacDevicePHIDType.php',
- 'AlmanacDeviceProperty' => 'applications/almanac/storage/AlmanacDeviceProperty.php',
'AlmanacDeviceQuery' => 'applications/almanac/query/AlmanacDeviceQuery.php',
'AlmanacDeviceSearchEngine' => 'applications/almanac/query/AlmanacDeviceSearchEngine.php',
'AlmanacDeviceTransaction' => 'applications/almanac/storage/AlmanacDeviceTransaction.php',
@@ -59,6 +60,11 @@
'AlmanacNetworkTransaction' => 'applications/almanac/storage/AlmanacNetworkTransaction.php',
'AlmanacNetworkTransactionQuery' => 'applications/almanac/query/AlmanacNetworkTransactionQuery.php',
'AlmanacNetworkViewController' => 'applications/almanac/controller/AlmanacNetworkViewController.php',
+ 'AlmanacProperty' => 'applications/almanac/storage/AlmanacProperty.php',
+ 'AlmanacPropertyController' => 'applications/almanac/controller/AlmanacPropertyController.php',
+ 'AlmanacPropertyEditController' => 'applications/almanac/controller/AlmanacPropertyEditController.php',
+ 'AlmanacPropertyInterface' => 'applications/almanac/property/AlmanacPropertyInterface.php',
+ 'AlmanacPropertyQuery' => 'applications/almanac/query/AlmanacPropertyQuery.php',
'AlmanacService' => 'applications/almanac/storage/AlmanacService.php',
'AlmanacServiceController' => 'applications/almanac/controller/AlmanacServiceController.php',
'AlmanacServiceEditController' => 'applications/almanac/controller/AlmanacServiceEditController.php',
@@ -2978,9 +2984,14 @@
'AlmanacConduitUtil' => 'Phobject',
'AlmanacConsoleController' => 'AlmanacController',
'AlmanacController' => 'PhabricatorController',
+ 'AlmanacCoreCustomField' => array(
+ 'AlmanacCustomField',
+ 'PhabricatorStandardCustomFieldInterface',
+ ),
'AlmanacCreateDevicesCapability' => 'PhabricatorPolicyCapability',
'AlmanacCreateNetworksCapability' => 'PhabricatorPolicyCapability',
'AlmanacCreateServicesCapability' => 'PhabricatorPolicyCapability',
+ 'AlmanacCustomField' => 'PhabricatorCustomField',
'AlmanacDAO' => 'PhabricatorLiskDAO',
'AlmanacDevice' => array(
'AlmanacDAO',
@@ -2991,7 +3002,6 @@
'AlmanacDeviceEditor' => 'PhabricatorApplicationTransactionEditor',
'AlmanacDeviceListController' => 'AlmanacDeviceController',
'AlmanacDevicePHIDType' => 'PhabricatorPHIDType',
- 'AlmanacDeviceProperty' => 'AlmanacDAO',
'AlmanacDeviceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'AlmanacDeviceSearchEngine' => 'PhabricatorApplicationSearchEngine',
'AlmanacDeviceTransaction' => 'PhabricatorApplicationTransaction',
@@ -3024,9 +3034,19 @@
'AlmanacNetworkTransaction' => 'PhabricatorApplicationTransaction',
'AlmanacNetworkTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'AlmanacNetworkViewController' => 'AlmanacNetworkController',
+ 'AlmanacProperty' => array(
+ 'PhabricatorCustomFieldStorage',
+ 'PhabricatorPolicyInterface',
+ ),
+ 'AlmanacPropertyController' => 'AlmanacController',
+ 'AlmanacPropertyEditController' => 'AlmanacDeviceController',
+ 'AlmanacPropertyQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'AlmanacService' => array(
'AlmanacDAO',
'PhabricatorPolicyInterface',
+ 'PhabricatorCustomFieldInterface',
+ 'PhabricatorApplicationTransactionInterface',
+ 'AlmanacPropertyInterface',
),
'AlmanacServiceController' => 'AlmanacController',
'AlmanacServiceEditController' => 'AlmanacServiceController',
diff --git a/src/applications/almanac/application/PhabricatorAlmanacApplication.php b/src/applications/almanac/application/PhabricatorAlmanacApplication.php
--- a/src/applications/almanac/application/PhabricatorAlmanacApplication.php
+++ b/src/applications/almanac/application/PhabricatorAlmanacApplication.php
@@ -56,6 +56,9 @@
'edit/(?:(?P<id>\d+)/)?' => 'AlmanacNetworkEditController',
'(?P<id>\d+)/' => 'AlmanacNetworkViewController',
),
+ 'property/' => array(
+ 'edit/(?:(?P<id>\d+)/)?' => 'AlmanacPropertyEditController',
+ ),
),
);
}
diff --git a/src/applications/almanac/controller/AlmanacController.php b/src/applications/almanac/controller/AlmanacController.php
--- a/src/applications/almanac/controller/AlmanacController.php
+++ b/src/applications/almanac/controller/AlmanacController.php
@@ -1,4 +1,65 @@
<?php
abstract class AlmanacController
- extends PhabricatorController {}
+ extends PhabricatorController {
+
+
+ protected function buildAlmanacPropertiesTable($object) {
+ $viewer = $this->getViewer();
+
+ $properties = id(new AlmanacPropertyQuery())
+ ->setViewer($viewer)
+ ->withObjectPHIDs(array($object->getPHID()))
+ ->execute();
+
+ $rows = array();
+ foreach ($properties as $property) {
+ $value = $property->getFieldValue();
+
+ $rows[] = array(
+ $property->getFieldName(),
+ PhabricatorConfigJSON::prettyPrintJSON($value),
+ );
+ }
+
+ $table = id(new AphrontTableView($rows))
+ ->setNoDataString(pht('No properties.'))
+ ->setHeaders(
+ array(
+ pht('Name'),
+ pht('Value'),
+ ))
+ ->setColumnClasses(
+ array(
+ null,
+ 'wide',
+ ));
+
+ $phid = $object->getPHID();
+ $add_uri = $this->getApplicationURI("property/edit/?objectPHID={$phid}");
+
+ $can_edit = PhabricatorPolicyFilter::hasCapability(
+ $viewer,
+ $object,
+ PhabricatorPolicyCapability::CAN_EDIT);
+
+ $add_button = id(new PHUIButtonView())
+ ->setTag('a')
+ ->setHref($add_uri)
+ ->setWorkflow(true)
+ ->setDisabled(!$can_edit)
+ ->setText(pht('Add Property'))
+ ->setIcon(
+ id(new PHUIIconView())
+ ->setIconFont('fa-plus'));
+
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('Properties'))
+ ->addActionLink($add_button);
+
+ return id(new PHUIObjectBoxView())
+ ->setHeader($header)
+ ->appendChild($table);
+ }
+
+}
diff --git a/src/applications/almanac/controller/AlmanacPropertyController.php b/src/applications/almanac/controller/AlmanacPropertyController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/almanac/controller/AlmanacPropertyController.php
@@ -0,0 +1,3 @@
+<?php
+
+abstract class AlmanacPropertyController extends AlmanacController {}
diff --git a/src/applications/almanac/controller/AlmanacPropertyEditController.php b/src/applications/almanac/controller/AlmanacPropertyEditController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/almanac/controller/AlmanacPropertyEditController.php
@@ -0,0 +1,169 @@
+<?php
+
+final class AlmanacPropertyEditController
+ extends AlmanacDeviceController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $request->getViewer();
+
+ $id = $request->getURIData('id');
+ if ($id) {
+ $property = id(new AlmanacPropertyQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$property) {
+ return new Aphront404Response();
+ }
+
+ $object = $property->getObject();
+
+ $is_new = false;
+ $title = pht('Edit Property');
+ $save_button = pht('Save Changes');
+ } else {
+ $object = id(new PhabricatorObjectQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($request->getStr('objectPHID')))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$object) {
+ return new Aphront404Response();
+ }
+
+ $is_new = true;
+ $title = pht('Add Property');
+ $save_button = pht('Add Property');
+ }
+
+ if (!($object instanceof AlmanacPropertyInterface)) {
+ return new Aphront404Response();
+ }
+
+ $cancel_uri = $object->getURI();
+
+ if ($is_new) {
+ $errors = array();
+ $property = null;
+
+ $v_name = null;
+ $e_name = true;
+
+ if ($request->isFormPost()) {
+ $name = $request->getStr('name');
+ if (!strlen($name)) {
+ $e_name = pht('Required');
+ $errors[] = pht('You must provide a property name.');
+ } else {
+ $caught = null;
+ try {
+ AlmanacNames::validateServiceOrDeviceName($name);
+ } catch (Exception $ex) {
+ $caught = $ex;
+ }
+ if ($caught) {
+ $e_name = pht('Invalid');
+ $errors[] = $caught->getMessage();
+ }
+ }
+
+ if (!$errors) {
+ $property = id(new AlmanacPropertyQuery())
+ ->setViewer($viewer)
+ ->withObjectPHIDs(array($object->getPHID()))
+ ->withNames(array($name))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$property) {
+ $property = id(new AlmanacProperty())
+ ->setObjectPHID($object->getPHID())
+ ->setFieldName($name);
+ }
+ }
+ }
+
+ if (!$property) {
+ $form = id(new AphrontFormView())
+ ->setUser($viewer)
+ ->appendChild(
+ id(new AphrontFormTextControl())
+ ->setName('name')
+ ->setLabel(pht('Name'))
+ ->setValue($v_name)
+ ->setError($e_name));
+
+ return $this->newDialog()
+ ->setTitle($title)
+ ->setErrors($errors)
+ ->addHiddenInput('objectPHID', $request->getStr('objectPHID'))
+ ->appendForm($form)
+ ->addSubmitButton(pht('Continue'))
+ ->addCancelButton($cancel_uri);
+ }
+ }
+
+ $v_name = $property->getFieldName();
+ $e_name = true;
+
+ $v_value = $property->getFieldValue();
+ $e_value = null;
+
+ $object->attachAlmanacProperties(array($property));
+
+ $field_list = PhabricatorCustomField::getObjectFields(
+ $object,
+ PhabricatorCustomField::ROLE_EDIT);
+ $field_list
+ ->setViewer($viewer)
+ ->readFieldsFromStorage($object);
+
+ $validation_exception = null;
+ if ($request->isFormPost() && $request->getStr('isValueEdit')) {
+ $xactions = $field_list->buildFieldTransactionsFromRequest(
+ $object->getApplicationTransactionTemplate(),
+ $request);
+
+ $editor = $object->getApplicationTransactionEditor()
+ ->setActor($viewer)
+ ->setContentSourceFromRequest($request)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true);
+
+ try {
+ $editor->applyTransactions($object, $xactions);
+ return id(new AphrontRedirectResponse())->setURI($cancel_uri);
+ } catch (PhabricatorApplicationTransactionValidationException $ex) {
+ $validation_exception = $ex;
+ }
+ }
+
+ $form = id(new AphrontFormView())
+ ->setUser($viewer)
+ ->addHiddenInput('objectPHID', $request->getStr('objectPHID'))
+ ->addHiddenInput('name', $request->getStr('name'))
+ ->addHiddenInput('isValueEdit', true);
+
+ $field_list->appendFieldsToForm($form);
+
+ return $this->newDialog()
+ ->setTitle($title)
+ ->setValidationException($validation_exception)
+ ->appendForm($form)
+ ->addSubmitButton($save_button)
+ ->addCancelButton($cancel_uri);
+ }
+
+}
diff --git a/src/applications/almanac/controller/AlmanacServiceViewController.php b/src/applications/almanac/controller/AlmanacServiceViewController.php
--- a/src/applications/almanac/controller/AlmanacServiceViewController.php
+++ b/src/applications/almanac/controller/AlmanacServiceViewController.php
@@ -15,6 +15,7 @@
$service = id(new AlmanacServiceQuery())
->setViewer($viewer)
->withNames(array($name))
+ ->needProperties(true)
->executeOne();
if (!$service) {
return new Aphront404Response();
@@ -56,6 +57,7 @@
$crumbs,
$box,
$bindings,
+ $this->buildAlmanacPropertiesTable($service),
$xaction_view,
),
array(
diff --git a/src/applications/almanac/customfield/AlmanacCoreCustomField.php b/src/applications/almanac/customfield/AlmanacCoreCustomField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/almanac/customfield/AlmanacCoreCustomField.php
@@ -0,0 +1,62 @@
+<?php
+
+final class AlmanacCoreCustomField
+ extends AlmanacCustomField
+ implements PhabricatorStandardCustomFieldInterface {
+
+ public function getStandardCustomFieldNamespace() {
+ return 'almanac:core';
+ }
+
+ public function createFields($object) {
+ $specs = array();
+
+ foreach ($object->getAlmanacProperties() as $property) {
+ $specs[$property->getFieldName()] = array(
+ 'name' => $property->getFieldName(),
+ 'type' => 'text',
+ );
+ }
+
+ return PhabricatorStandardCustomField::buildStandardFields($this, $specs);
+ }
+
+ public function shouldUseStorage() {
+ return false;
+ }
+
+ public function readValueFromObject(PhabricatorCustomFieldInterface $object) {
+ $key = $this->getProxy()->getRawStandardFieldKey();
+ $this->setValueFromStorage($object->getAlmanacPropertyValue($key));
+ }
+
+ public function applyApplicationTransactionInternalEffects(
+ PhabricatorApplicationTransaction $xaction) {
+ return;
+ }
+
+ public function applyApplicationTransactionExternalEffects(
+ PhabricatorApplicationTransaction $xaction) {
+
+ $object = $this->getObject();
+ $phid = $object->getPHID();
+ $key = $this->getProxy()->getRawStandardFieldKey();
+
+ $property = id(new AlmanacPropertyQuery())
+ ->setViewer($this->getViewer())
+ ->withObjectPHIDs(array($phid))
+ ->withNames(array($key))
+ ->executeOne();
+ if (!$property) {
+ $property = id(new AlmanacProperty())
+ ->setObjectPHID($phid)
+ ->setFieldIndex(PhabricatorHash::digestForIndex($key))
+ ->setFieldName($key);
+ }
+
+ $property
+ ->setFieldValue($xaction->getNewValue())
+ ->save();
+ }
+
+}
diff --git a/src/applications/almanac/customfield/AlmanacCustomField.php b/src/applications/almanac/customfield/AlmanacCustomField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/almanac/customfield/AlmanacCustomField.php
@@ -0,0 +1,4 @@
+<?php
+
+abstract class AlmanacCustomField
+ extends PhabricatorCustomField {}
diff --git a/src/applications/almanac/management/AlmanacManagementRegisterWorkflow.php b/src/applications/almanac/management/AlmanacManagementRegisterWorkflow.php
--- a/src/applications/almanac/management/AlmanacManagementRegisterWorkflow.php
+++ b/src/applications/almanac/management/AlmanacManagementRegisterWorkflow.php
@@ -25,15 +25,15 @@
->setName(php_uname('n'))
->save();
- id(new AlmanacDeviceProperty())
- ->setDevicePHID($host->getPHID())
- ->setKey('conduitPublicOpenSSHKey')
+ id(new AlmanacProperty())
+ ->setObjectPHID($host->getPHID())
+ ->setName('conduitPublicOpenSSHKey')
->setValue($public_key)
->save();
- id(new AlmanacDeviceProperty())
- ->setDevicePHID($host->getPHID())
- ->setKey('conduitPublicOpenSSLKey')
+ id(new AlmanacProperty())
+ ->setObjectPHID($host->getPHID())
+ ->setName('conduitPublicOpenSSLKey')
->setValue($this->convertToOpenSSLPublicKey($public_key))
->save();
diff --git a/src/applications/almanac/property/AlmanacPropertyInterface.php b/src/applications/almanac/property/AlmanacPropertyInterface.php
new file mode 100644
--- /dev/null
+++ b/src/applications/almanac/property/AlmanacPropertyInterface.php
@@ -0,0 +1,11 @@
+<?php
+
+interface AlmanacPropertyInterface {
+
+ public function attachAlmanacProperties(array $properties);
+ public function getAlmanacProperties();
+ public function hasAlmanacProperty($key);
+ public function getAlmanacProperty($key);
+ public function getAlmanacPropertyValue($key, $default = null);
+
+}
diff --git a/src/applications/almanac/query/AlmanacServiceQuery.php b/src/applications/almanac/query/AlmanacPropertyQuery.php
copy from src/applications/almanac/query/AlmanacServiceQuery.php
copy to src/applications/almanac/query/AlmanacPropertyQuery.php
--- a/src/applications/almanac/query/AlmanacServiceQuery.php
+++ b/src/applications/almanac/query/AlmanacPropertyQuery.php
@@ -1,18 +1,12 @@
<?php
-final class AlmanacServiceQuery
+final class AlmanacPropertyQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
- private $ids;
- private $phids;
+ private $objectPHIDs;
private $names;
- public function withIDs(array $ids) {
- $this->ids = $ids;
- return $this;
- }
-
- public function withPHIDs(array $phids) {
+ public function withObjectPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
@@ -23,7 +17,7 @@
}
protected function loadPage() {
- $table = new AlmanacService();
+ $table = new AlmanacProperty();
$conn_r = $table->establishConnection('r');
$data = queryfx_all(
@@ -37,21 +31,36 @@
return $table->loadAllFromArray($data);
}
+ protected function willFilterPage(array $properties) {
+ $object_phids = mpull($properties, 'getObjectPHID');
+
+ $objects = id(new PhabricatorObjectQuery())
+ ->setViewer($this->getViewer())
+ ->setParentQuery($this)
+ ->withPHIDs($object_phids)
+ ->execute();
+ $objects = mpull($objects, null, 'getPHID');
+
+ foreach ($properties as $key => $property) {
+ $object = idx($objects, $property->getObjectPHID());
+ if (!$object) {
+ unset($properties[$key]);
+ continue;
+ }
+ $property->attachObject($object);
+ }
+
+ return $properties;
+ }
+
protected function buildWhereClause($conn_r) {
$where = array();
- if ($this->ids !== null) {
- $where[] = qsprintf(
- $conn_r,
- 'id IN (%Ld)',
- $this->ids);
- }
-
- if ($this->phids !== null) {
+ if ($this->objectPHIDs !== null) {
$where[] = qsprintf(
$conn_r,
- 'phid IN (%Ls)',
- $this->phids);
+ 'objectPHID IN (%Ls)',
+ $this->objectPHIDs);
}
if ($this->names !== null) {
@@ -59,10 +68,9 @@
foreach ($this->names as $name) {
$hashes[] = PhabricatorHash::digestForIndex($name);
}
-
$where[] = qsprintf(
$conn_r,
- 'nameIndex IN (%Ls)',
+ 'fieldIndex IN (%Ls)',
$hashes);
}
diff --git a/src/applications/almanac/query/AlmanacServiceQuery.php b/src/applications/almanac/query/AlmanacServiceQuery.php
--- a/src/applications/almanac/query/AlmanacServiceQuery.php
+++ b/src/applications/almanac/query/AlmanacServiceQuery.php
@@ -6,6 +6,7 @@
private $ids;
private $phids;
private $names;
+ private $needProperties;
public function withIDs(array $ids) {
$this->ids = $ids;
@@ -22,6 +23,11 @@
return $this;
}
+ public function needProperties($need) {
+ $this->needProperties = $need;
+ return $this;
+ }
+
protected function loadPage() {
$table = new AlmanacService();
$conn_r = $table->establishConnection('r');
@@ -71,6 +77,25 @@
return $this->formatWhereClause($where);
}
+ protected function didFilterPage(array $services) {
+ // NOTE: We load properties unconditionally because CustomField assumes
+ // it can always generate a list of fields on an object. It may make
+ // sense to re-examine that assumption eventually.
+
+ $properties = id(new AlmanacPropertyQuery())
+ ->setViewer($this->getViewer())
+ ->setParentQuery($this)
+ ->withObjectPHIDs(mpull($services, null, 'getPHID'))
+ ->execute();
+ $properties = mgroup($properties, 'getObjectPHID');
+ foreach ($services as $service) {
+ $service_properties = idx($properties, $service->getPHID(), array());
+ $service->attachAlmanacProperties($service_properties);
+ }
+
+ return $services;
+ }
+
public function getQueryApplicationClass() {
return 'PhabricatorAlmanacApplication';
}
diff --git a/src/applications/almanac/storage/AlmanacDeviceProperty.php b/src/applications/almanac/storage/AlmanacDeviceProperty.php
deleted file mode 100644
--- a/src/applications/almanac/storage/AlmanacDeviceProperty.php
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-
-final class AlmanacDeviceProperty extends AlmanacDAO {
-
- protected $devicePHID;
- protected $key;
- protected $value;
-
- public function getConfiguration() {
- return array(
- self::CONFIG_SERIALIZATION => array(
- 'value' => self::SERIALIZATION_JSON,
- ),
- self::CONFIG_COLUMN_SCHEMA => array(
- 'key' => 'text128',
- ),
- self::CONFIG_KEY_SCHEMA => array(
- 'key_device' => array(
- 'columns' => array('devicePHID', 'key'),
- ),
- ),
- ) + parent::getConfiguration();
- }
-
-}
diff --git a/src/applications/almanac/storage/AlmanacProperty.php b/src/applications/almanac/storage/AlmanacProperty.php
new file mode 100644
--- /dev/null
+++ b/src/applications/almanac/storage/AlmanacProperty.php
@@ -0,0 +1,56 @@
+<?php
+
+final class AlmanacProperty
+ extends PhabricatorCustomFieldStorage
+ implements PhabricatorPolicyInterface {
+
+ protected $fieldName;
+
+ private $object = self::ATTACHABLE;
+
+ public function getApplicationName() {
+ return 'almanac';
+ }
+
+ public function getConfiguration() {
+ $config = parent::getConfiguration();
+
+ $config[self::CONFIG_COLUMN_SCHEMA] += array(
+ 'fieldName' => 'text128',
+ );
+
+ return $config;
+ }
+
+ public function getObject() {
+ return $this->assertAttached($this->object);
+ }
+
+ public function attachObject(PhabricatorLiskDAO $object) {
+ $this->object = $object;
+ return $this;
+ }
+
+/* -( PhabricatorPolicyInterface )----------------------------------------- */
+
+
+ public function getCapabilities() {
+ return array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ );
+ }
+
+ public function getPolicy($capability) {
+ return $this->getObject()->getPolicy($capability);
+ }
+
+ public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
+ return $this->getObject()->hasAutomaticCapability($capability, $viewer);
+ }
+
+ public function describeAutomaticCapability($capability) {
+ return pht('Properties inherit the policies of their object.');
+ }
+
+}
diff --git a/src/applications/almanac/storage/AlmanacService.php b/src/applications/almanac/storage/AlmanacService.php
--- a/src/applications/almanac/storage/AlmanacService.php
+++ b/src/applications/almanac/storage/AlmanacService.php
@@ -2,7 +2,11 @@
final class AlmanacService
extends AlmanacDAO
- implements PhabricatorPolicyInterface {
+ implements
+ PhabricatorPolicyInterface,
+ PhabricatorCustomFieldInterface,
+ PhabricatorApplicationTransactionInterface,
+ AlmanacPropertyInterface {
protected $name;
protected $nameIndex;
@@ -10,6 +14,9 @@
protected $viewPolicy;
protected $editPolicy;
+ private $customFields = self::ATTACHABLE;
+ private $almanacProperties = self::ATTACHABLE;
+
public static function initializeNewService() {
return id(new AlmanacService())
->setViewPolicy(PhabricatorPolicies::POLICY_USER)
@@ -56,6 +63,38 @@
return '/almanac/service/view/'.$this->getName().'/';
}
+
+/* -( AlmanacPropertyInterface )------------------------------------------- */
+
+
+ public function attachAlmanacProperties(array $properties) {
+ assert_instances_of($properties, 'AlmanacProperty');
+ $this->almanacProperties = mpull($properties, null, 'getFieldName');
+ return $this;
+ }
+
+ public function getAlmanacProperties() {
+ return $this->assertAttached($this->almanacProperties);
+ }
+
+ public function hasAlmanacProperty($key) {
+ $this->assertAttached($this->almanacProperties);
+ return isset($this->almanacProperties[$key]);
+ }
+
+ public function getAlmanacProperty($key) {
+ return $this->assertAttachedKey($this->almanacProperties, $key);
+ }
+
+ public function getAlmanacPropertyValue($key, $default = null) {
+ if ($this->hasAlmanacProperty($key)) {
+ return $this->getAlmanacProperty($key)->getFieldValue();
+ } else {
+ return $default;
+ }
+ }
+
+
/* -( PhabricatorPolicyInterface )----------------------------------------- */
@@ -83,4 +122,41 @@
return null;
}
+
+/* -( PhabricatorCustomFieldInterface )------------------------------------ */
+
+
+ public function getCustomFieldSpecificationForRole($role) {
+ return array();
+ }
+
+ public function getCustomFieldBaseClass() {
+ return 'AlmanacCustomField';
+ }
+
+ public function getCustomFields() {
+ return $this->assertAttached($this->customFields);
+ }
+
+ public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) {
+ $this->customFields = $fields;
+ return $this;
+ }
+
+
+/* -( PhabricatorApplicationTransactionInterface )------------------------- */
+
+
+ public function getApplicationTransactionEditor() {
+ return new AlmanacServiceEditor();
+ }
+
+ public function getApplicationTransactionObject() {
+ return $this;
+ }
+
+ public function getApplicationTransactionTemplate() {
+ return new AlmanacServiceTransaction();
+ }
+
}
diff --git a/src/applications/transactions/query/PhabricatorApplicationTransactionQuery.php b/src/applications/transactions/query/PhabricatorApplicationTransactionQuery.php
--- a/src/applications/transactions/query/PhabricatorApplicationTransactionQuery.php
+++ b/src/applications/transactions/query/PhabricatorApplicationTransactionQuery.php
@@ -119,7 +119,7 @@
// NOTE: We have to do this after loading objects, because the objects
// may help determine which handles are required (for example, in the case
- // of custom fields.
+ // of custom fields).
if ($this->needHandles) {
$phids = array();
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jan 16, 3:30 AM (19 h, 12 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6995903
Default Alt Text
D10777.diff (28 KB)
Attached To
Mode
D10777: Give Almanac generic, custom-field-based properties
Attached
Detach File
Event Timeline
Log In to Comment