Page MenuHomePhabricator

D13091.id31821.diff
No OneTemporary

D13091.id31821.diff

diff --git a/resources/sql/autopatches/20150605.diviner.edges.sql b/resources/sql/autopatches/20150605.diviner.edges.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20150605.diviner.edges.sql
@@ -0,0 +1,17 @@
+CREATE TABLE {$NAMESPACE}_diviner.edge (
+ src VARBINARY(64) NOT NULL,
+ type INT UNSIGNED NOT NULL,
+ dst VARBINARY(64) NOT NULL,
+ dateCreated INT UNSIGNED NOT NULL,
+ seq INT UNSIGNED NOT NULL,
+ dataID INT UNSIGNED,
+
+ PRIMARY KEY (src, type, dst),
+ KEY src (src, type, dateCreated, seq),
+ UNIQUE KEY key_dst (dst, type, src)
+) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
+
+CREATE TABLE {$NAMESPACE}_diviner.edgedata (
+ id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ data LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}
+) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
diff --git a/resources/sql/autopatches/20150605.diviner.editPolicy.sql b/resources/sql/autopatches/20150605.diviner.editPolicy.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20150605.diviner.editPolicy.sql
@@ -0,0 +1,6 @@
+ALTER TABLE {$NAMESPACE}_diviner.diviner_livebook
+ ADD COLUMN editPolicy VARBINARY(64) NOT NULL AFTER viewPolicy;
+
+UPDATE {$NAMESPACE}_diviner.diviner_livebook
+ SET editPolicy = 'admin'
+ WHERE editPolicy IS NULL;
diff --git a/resources/sql/autopatches/20150605.diviner.xaction.sql b/resources/sql/autopatches/20150605.diviner.xaction.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20150605.diviner.xaction.sql
@@ -0,0 +1,19 @@
+CREATE TABLE {$NAMESPACE}_diviner.diviner_livebooktransaction (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ phid VARBINARY(64) NOT NULL,
+ authorPHID VARBINARY(64) NOT NULL,
+ objectPHID VARBINARY(64) NOT NULL,
+ viewPolicy VARBINARY(64) NOT NULL,
+ editPolicy VARBINARY(64) NOT NULL,
+ commentPHID VARBINARY(64) DEFAULT NULL,
+ commentVersion INT UNSIGNED NOT NULL,
+ transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL,
+ oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
+ newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
+ contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
+ metadata LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
+ dateCreated INT UNSIGNED NOT NULL,
+ dateModified INT UNSIGNED NOT NULL,
+ UNIQUE KEY key_phid (phid),
+ KEY key_object (objectPHID)
+) 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
@@ -646,19 +646,24 @@
'DivinerAtomizeWorkflow' => 'applications/diviner/workflow/DivinerAtomizeWorkflow.php',
'DivinerAtomizer' => 'applications/diviner/atomizer/DivinerAtomizer.php',
'DivinerBookController' => 'applications/diviner/controller/DivinerBookController.php',
+ 'DivinerBookEditController' => 'applications/diviner/controller/DivinerBookEditController.php',
'DivinerBookItemView' => 'applications/diviner/view/DivinerBookItemView.php',
'DivinerBookPHIDType' => 'applications/diviner/phid/DivinerBookPHIDType.php',
'DivinerBookQuery' => 'applications/diviner/query/DivinerBookQuery.php',
'DivinerBookSearchIndexer' => 'applications/diviner/search/DivinerBookSearchIndexer.php',
'DivinerController' => 'applications/diviner/controller/DivinerController.php',
'DivinerDAO' => 'applications/diviner/storage/DivinerDAO.php',
+ 'DivinerDefaultEditCapability' => 'applications/diviner/capability/DivinerDefaultEditCapability.php',
'DivinerDefaultRenderer' => 'applications/diviner/renderer/DivinerDefaultRenderer.php',
+ 'DivinerDefaultViewCapability' => 'applications/diviner/capability/DivinerDefaultViewCapability.php',
'DivinerDiskCache' => 'applications/diviner/cache/DivinerDiskCache.php',
'DivinerFileAtomizer' => 'applications/diviner/atomizer/DivinerFileAtomizer.php',
'DivinerFindController' => 'applications/diviner/controller/DivinerFindController.php',
'DivinerGenerateWorkflow' => 'applications/diviner/workflow/DivinerGenerateWorkflow.php',
'DivinerLiveAtom' => 'applications/diviner/storage/DivinerLiveAtom.php',
'DivinerLiveBook' => 'applications/diviner/storage/DivinerLiveBook.php',
+ 'DivinerLiveBookEditor' => 'applications/diviner/editor/DivinerLiveBookEditor.php',
+ 'DivinerLiveBookTransaction' => 'applications/diviner/storage/DivinerLiveBookTransaction.php',
'DivinerLivePublisher' => 'applications/diviner/publisher/DivinerLivePublisher.php',
'DivinerLiveSymbol' => 'applications/diviner/storage/DivinerLiveSymbol.php',
'DivinerMainController' => 'applications/diviner/controller/DivinerMainController.php',
@@ -668,6 +673,7 @@
'DivinerPublisher' => 'applications/diviner/publisher/DivinerPublisher.php',
'DivinerRenderer' => 'applications/diviner/renderer/DivinerRenderer.php',
'DivinerReturnTableView' => 'applications/diviner/view/DivinerReturnTableView.php',
+ 'DivinerSchemaSpec' => 'applications/diviner/storage/DivinerSchemaSpec.php',
'DivinerSectionView' => 'applications/diviner/view/DivinerSectionView.php',
'DivinerStaticPublisher' => 'applications/diviner/publisher/DivinerStaticPublisher.php',
'DivinerSymbolRemarkupRule' => 'applications/diviner/markup/DivinerSymbolRemarkupRule.php',
@@ -3890,13 +3896,16 @@
'DivinerAtomSearchIndexer' => 'PhabricatorSearchDocumentIndexer',
'DivinerAtomizeWorkflow' => 'DivinerWorkflow',
'DivinerBookController' => 'DivinerController',
+ 'DivinerBookEditController' => 'DivinerController',
'DivinerBookItemView' => 'AphrontTagView',
'DivinerBookPHIDType' => 'PhabricatorPHIDType',
'DivinerBookQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'DivinerBookSearchIndexer' => 'PhabricatorSearchDocumentIndexer',
'DivinerController' => 'PhabricatorController',
'DivinerDAO' => 'PhabricatorLiskDAO',
+ 'DivinerDefaultEditCapability' => 'PhabricatorPolicyCapability',
'DivinerDefaultRenderer' => 'DivinerRenderer',
+ 'DivinerDefaultViewCapability' => 'PhabricatorPolicyCapability',
'DivinerFileAtomizer' => 'DivinerAtomizer',
'DivinerFindController' => 'DivinerController',
'DivinerGenerateWorkflow' => 'DivinerWorkflow',
@@ -3904,8 +3913,11 @@
'DivinerLiveBook' => array(
'DivinerDAO',
'PhabricatorPolicyInterface',
+ 'PhabricatorProjectInterface',
'PhabricatorDestructibleInterface',
),
+ 'DivinerLiveBookEditor' => 'PhabricatorApplicationTransactionEditor',
+ 'DivinerLiveBookTransaction' => 'PhabricatorApplicationTransaction',
'DivinerLivePublisher' => 'DivinerPublisher',
'DivinerLiveSymbol' => array(
'DivinerDAO',
@@ -3918,6 +3930,7 @@
'DivinerParameterTableView' => 'AphrontTagView',
'DivinerPublishCache' => 'DivinerDiskCache',
'DivinerReturnTableView' => 'AphrontTagView',
+ 'DivinerSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'DivinerSectionView' => 'AphrontTagView',
'DivinerStaticPublisher' => 'DivinerPublisher',
'DivinerSymbolRemarkupRule' => 'PhutilRemarkupRule',
diff --git a/src/applications/diviner/application/PhabricatorDivinerApplication.php b/src/applications/diviner/application/PhabricatorDivinerApplication.php
--- a/src/applications/diviner/application/PhabricatorDivinerApplication.php
+++ b/src/applications/diviner/application/PhabricatorDivinerApplication.php
@@ -39,6 +39,7 @@
'find/' => 'DivinerFindController',
),
'/book/(?P<book>[^/]+)/' => 'DivinerBookController',
+ '/book/(?P<book>[^/]+)/edit/' => 'DivinerBookEditController',
'/book/'.
'(?P<book>[^/]+)/'.
'(?P<type>[^/]+)/'.
@@ -52,6 +53,15 @@
return self::GROUP_UTILITIES;
}
+ protected function getCustomCapabilities() {
+ return array(
+ DivinerDefaultViewCapability::CAPABILITY => array(),
+ DivinerDefaultEditCapability::CAPABILITY => array(
+ 'default' => PhabricatorPolicies::POLICY_ADMIN,
+ ),
+ );
+ }
+
public function getRemarkupRules() {
return array(
new DivinerSymbolRemarkupRule(),
diff --git a/src/applications/diviner/capability/DivinerDefaultEditCapability.php b/src/applications/diviner/capability/DivinerDefaultEditCapability.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diviner/capability/DivinerDefaultEditCapability.php
@@ -0,0 +1,11 @@
+<?php
+
+final class DivinerDefaultEditCapability extends PhabricatorPolicyCapability {
+
+ const CAPABILITY = 'diviner.default.edit';
+
+ public function getCapabilityName() {
+ return pht('Default Edit Policy');
+ }
+
+}
diff --git a/src/applications/diviner/capability/DivinerDefaultViewCapability.php b/src/applications/diviner/capability/DivinerDefaultViewCapability.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diviner/capability/DivinerDefaultViewCapability.php
@@ -0,0 +1,15 @@
+<?php
+
+final class DivinerDefaultViewCapability extends PhabricatorPolicyCapability {
+
+ const CAPABILITY = 'diviner.default.view';
+
+ public function getCapabilityName() {
+ return pht('Default View Policy');
+ }
+
+ public function shouldAllowPublicPolicySetting() {
+ return true;
+ }
+
+}
diff --git a/src/applications/diviner/controller/DivinerBookEditController.php b/src/applications/diviner/controller/DivinerBookEditController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diviner/controller/DivinerBookEditController.php
@@ -0,0 +1,91 @@
+<?php
+
+final class DivinerBookEditController extends DivinerController {
+
+ private $bookName;
+
+ public function willProcessRequest(array $data) {
+ $this->bookName = $data['book'];
+ }
+
+ protected function processRequest() {
+ $request = $this->getRequest();
+ $user = $request->getUser();
+
+ $book = id(new DivinerBookQuery())
+ ->setViewer($user)
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->needProjectPHIDs(true)
+ ->withNames(array($this->bookName))
+ ->executeOne();
+
+ $view_uri = '/book/'.$book->getName();
+ $edit_uri = '/book/'.$book->getName().'/edit/';
+
+ if (!$book) {
+ return new Aphront404Response();
+ }
+
+ if ($request->isFormPost()) {
+ $v_projects = $request->getArr('projectPHIDs');
+
+ $xactions = array();
+ $template = id(new DivinerLiveBookTransaction());
+
+ $xactions[] = id(clone $template)
+ ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
+ ->setMetadataValue(
+ 'edge:type',
+ PhabricatorProjectObjectHasProjectEdgeType::EDGECONST)
+ ->setNewValue(
+ array(
+ '=' => array_fuse($v_projects),
+ ));
+
+ id(new DivinerLiveBookEditor())
+ ->setContinueOnNoEffect(true)
+ ->setContentSourceFromRequest($request)
+ ->setActor($user)
+ ->applyTransactions($book, $xactions);
+
+ return id(new AphrontRedirectResponse())->setURI($view_uri);
+ }
+
+ $crumbs = $this->buildApplicationCrumbs();
+ $crumbs->addTextCrumb(pht('Edit Basics'));
+
+ $title = pht('Edit %s', $book->getTitle());
+
+ $form = id(new AphrontFormView())
+ ->setUser($user)
+ ->appendControl(
+ id(new AphrontFormTokenizerControl())
+ ->setDatasource(new PhabricatorProjectDatasource())
+ ->setName('projectPHIDs')
+ ->setLabel(pht('Projects'))
+ ->setValue($book->getProjectPHIDs()))
+ ->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->setValue(pht('Save'))
+ ->addCancelButton($view_uri))
+ ->appendChild(id(new PHUIFormDividerControl()));
+
+ $object_box = id(new PHUIObjectBoxView())
+ ->setHeaderText($title)
+ ->setForm($form);
+
+ return $this->buildApplicationPage(
+ array(
+ $crumbs,
+ $object_box,
+ ),
+ array(
+ 'title' => $title,
+ ));
+ }
+
+}
diff --git a/src/applications/diviner/editor/DivinerLiveBookEditor.php b/src/applications/diviner/editor/DivinerLiveBookEditor.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diviner/editor/DivinerLiveBookEditor.php
@@ -0,0 +1,121 @@
+<?php
+
+final class DivinerLiveBookEditor
+ extends PhabricatorApplicationTransactionEditor {
+
+ public function getEditorApplicationClass() {
+ return 'PhabricatorDivinerApplication';
+ }
+
+ public function getEditorObjectsDescription() {
+ return pht('Books');
+ }
+
+ public function getTransactionTypes() {
+ $types = parent::getTransactionTypes();
+
+ $types[] = DivinerLiveBookTransaction::TYPE_REPOSITORY;
+
+ $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
+ $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
+
+ return $types;
+ }
+
+ protected function getCustomTransactionOldValue(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case DivinerLiveBookTransaction::TYPE_REPOSITORY:
+ return $object->getRepositoryPHID();
+ }
+ }
+
+ protected function getCustomTransactionNewValue(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case DivinerLiveBookTransaction::TYPE_REPOSITORY:
+ return $xaction->getNewValue();
+ }
+ }
+
+ protected function applyCustomInternalTransaction(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case DivinerLiveBookTransaction::TYPE_REPOSITORY:
+ $object->setRepositoryPHID($xaction->getNewValue());
+ break;
+ }
+ }
+
+ protected function applyCustomExternalTransaction(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case DivinerLiveBookTransaction::TYPE_REPOSITORY:
+ break;
+ }
+
+ }
+
+ protected function mergeTransactions(
+ PhabricatorApplicationTransaction $u,
+ PhabricatorApplicationTransaction $v) {
+
+ $type = $u->getTransactionType();
+ switch ($type) {}
+
+ return parent::mergeTransactions($u, $v);
+ }
+
+ protected function transactionHasEffect(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ $old = $xaction->getOldValue();
+ $new = $xaction->getNewValue();
+
+ $type = $xaction->getTransactionType();
+ switch ($type) {}
+
+ return parent::transactionHasEffect($object, $xaction);
+ }
+
+ protected function requireCapabilities(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case DivinerLiveBookTransaction::TYPE_REPOSITORY:
+ PhabricatorPolicyFilter::requireCapability(
+ $this->requireActor(),
+ $object,
+ PhabricatorPolicyCapability::CAN_EDIT);
+ break;
+ }
+ }
+
+ protected function validateTransaction(
+ PhabricatorLiskDAO $object,
+ $type,
+ array $xactions) {
+
+ $errors = parent::validateTransaction($object, $type, $xactions);
+
+ switch ($type) {
+ case DivinerLiveBookTransaction::TYPE_REPOSITORY:
+ // TODO: Implement this;
+ $ok = true;
+ break;
+ }
+
+ return $errors;
+ }
+
+}
diff --git a/src/applications/diviner/query/DivinerBookQuery.php b/src/applications/diviner/query/DivinerBookQuery.php
--- a/src/applications/diviner/query/DivinerBookQuery.php
+++ b/src/applications/diviner/query/DivinerBookQuery.php
@@ -6,6 +6,8 @@
private $phids;
private $names;
+ private $needProjectPHIDs;
+
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
@@ -21,6 +23,11 @@
return $this;
}
+ public function needProjectPHIDs($need_phids) {
+ $this->needProjectPHIDs = $need_phids;
+ return $this;
+ }
+
protected function loadPage() {
$table = new DivinerLiveBook();
$conn_r = $table->establishConnection('r');
@@ -36,6 +43,27 @@
return $table->loadAllFromArray($data);
}
+ protected function didFilterPage(array $books) {
+ if ($this->needProjectPHIDs) {
+ $type_project = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
+
+ $edge_query = id(new PhabricatorEdgeQuery())
+ ->withSourcePHIDs(mpull($books, 'getPHID'))
+ ->withEdgeTypes(array($type_project));
+ $edge_query->execute();
+
+ foreach ($books as $book) {
+ $project_phids = $edge_query->getDestinationPHIDs(
+ array(
+ $book->getPHID(),
+ ));
+ $book->attachProjectPHIDs($project_phids);
+ }
+ }
+
+ return $books;
+ }
+
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
$where = array();
diff --git a/src/applications/diviner/storage/DivinerLiveBook.php b/src/applications/diviner/storage/DivinerLiveBook.php
--- a/src/applications/diviner/storage/DivinerLiveBook.php
+++ b/src/applications/diviner/storage/DivinerLiveBook.php
@@ -3,12 +3,16 @@
final class DivinerLiveBook extends DivinerDAO
implements
PhabricatorPolicyInterface,
+ PhabricatorProjectInterface,
PhabricatorDestructibleInterface {
protected $name;
protected $viewPolicy;
+ protected $editPolicy;
protected $configurationData = array();
+ private $projectPHIDs = self::ATTACHABLE;
+
protected function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
@@ -63,20 +67,36 @@
return idx($spec, 'name', $group);
}
+ public function attachProjectPHIDs(array $project_phids) {
+ $this->projectPHIDs = $project_phids;
+ return $this;
+ }
+
+ public function getProjectPHIDs() {
+ return $this->assertAttached($this->projectPHIDs);
+ }
+
+
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
);
}
public function getPolicy($capability) {
- return PhabricatorPolicies::getMostOpenPolicy();
+ switch ($capability) {
+ case PhabricatorPolicyCapability::CAN_VIEW:
+ return $this->getViewPolicy();
+ case PhabricatorPolicyCapability::CAN_EDIT:
+ return $this->getEditPolicy();
+ }
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
- return false;
+ return false;
}
public function describeAutomaticCapability($capability) {
diff --git a/src/applications/diviner/storage/DivinerLiveBookTransaction.php b/src/applications/diviner/storage/DivinerLiveBookTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diviner/storage/DivinerLiveBookTransaction.php
@@ -0,0 +1,20 @@
+<?php
+
+final class DivinerLiveBookTransaction
+ extends PhabricatorApplicationTransaction {
+
+ const TYPE_REPOSITORY = 'book:repo';
+
+ public function getApplicationName() {
+ return 'diviner';
+ }
+
+ public function getApplicationTransactionType() {
+ return DivinerBookPHIDType::TYPECONST;
+ }
+
+ public function getApplicationTransactionCommentObject() {
+ return null;
+ }
+
+}
diff --git a/src/applications/diviner/storage/DivinerSchemaSpec.php b/src/applications/diviner/storage/DivinerSchemaSpec.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diviner/storage/DivinerSchemaSpec.php
@@ -0,0 +1,9 @@
+<?php
+
+final class DivinerSchemaSpec extends PhabricatorConfigSchemaSpec {
+
+ public function buildSchemata() {
+ $this->buildEdgeSchemata(new DivinerLiveBook());
+ }
+
+}

File Metadata

Mime Type
text/plain
Expires
Thu, May 1, 1:01 PM (1 w, 6 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7700401
Default Alt Text
D13091.id31821.diff (19 KB)

Event Timeline