Page MenuHomePhabricator

D10777.diff
No OneTemporary

D10777.diff

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

Mime Type
text/plain
Expires
Sun, May 12, 10:07 AM (2 w, 5 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6291099
Default Alt Text
D10777.diff (28 KB)

Event Timeline