diff --git a/resources/sql/autopatches/20151219.proj.01.prislug.sql b/resources/sql/autopatches/20151219.proj.01.prislug.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20151219.proj.01.prislug.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_project.project + ADD COLUMN primarySlug VARCHAR(128) COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20151219.proj.02.prislugkey.sql b/resources/sql/autopatches/20151219.proj.02.prislugkey.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20151219.proj.02.prislugkey.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_project.project + ADD UNIQUE KEY `key_primaryslug` (primarySlug); diff --git a/resources/sql/autopatches/20151219.proj.03.copyslug.sql b/resources/sql/autopatches/20151219.proj.03.copyslug.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20151219.proj.03.copyslug.sql @@ -0,0 +1,2 @@ +UPDATE {$NAMESPACE}_project.project + SET primarySlug = TRIM(TRAILING "/" FROM phrictionSlug); diff --git a/resources/sql/autopatches/20151219.proj.04.dropslugkey.sql b/resources/sql/autopatches/20151219.proj.04.dropslugkey.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20151219.proj.04.dropslugkey.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_project.project + DROP KEY `phrictionSlug`; diff --git a/resources/sql/autopatches/20151219.proj.05.dropslug.sql b/resources/sql/autopatches/20151219.proj.05.dropslug.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20151219.proj.05.dropslug.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_project.project + DROP COLUMN phrictionSlug; diff --git a/resources/sql/autopatches/20151219.proj.06.defaultpolicy.php b/resources/sql/autopatches/20151219.proj.06.defaultpolicy.php new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20151219.proj.06.defaultpolicy.php @@ -0,0 +1,28 @@ +getPolicy(ProjectDefaultViewCapability::CAPABILITY); +$edit_policy = $app->getPolicy(ProjectDefaultEditCapability::CAPABILITY); +$join_policy = $app->getPolicy(ProjectDefaultJoinCapability::CAPABILITY); + +$table = new PhabricatorProject(); +$conn_w = $table->establishConnection('w'); + +queryfx( + $conn_w, + 'UPDATE %T SET viewPolicy = %s WHERE viewPolicy IS NULL', + $table->getTableName(), + $view_policy); + +queryfx( + $conn_w, + 'UPDATE %T SET editPolicy = %s WHERE editPolicy IS NULL', + $table->getTableName(), + $edit_policy); + +queryfx( + $conn_w, + 'UPDATE %T SET joinPolicy = %s WHERE joinPolicy IS NULL', + $table->getTableName(), + $join_policy); diff --git a/resources/sql/autopatches/20151219.proj.07.viewnull.sql b/resources/sql/autopatches/20151219.proj.07.viewnull.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20151219.proj.07.viewnull.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_project.project + CHANGE viewPolicy viewPolicy VARBINARY(64) NOT NULL; diff --git a/resources/sql/autopatches/20151219.proj.08.editnull.sql b/resources/sql/autopatches/20151219.proj.08.editnull.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20151219.proj.08.editnull.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_project.project + CHANGE editPolicy editPolicy VARBINARY(64) NOT NULL; diff --git a/resources/sql/autopatches/20151219.proj.09.joinnull.sql b/resources/sql/autopatches/20151219.proj.09.joinnull.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20151219.proj.09.joinnull.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_project.project + CHANGE joinPolicy joinPolicy VARBINARY(64) NOT NULL; diff --git a/resources/sql/autopatches/20151219.proj.10.subcolumns.sql b/resources/sql/autopatches/20151219.proj.10.subcolumns.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20151219.proj.10.subcolumns.sql @@ -0,0 +1,17 @@ +ALTER TABLE {$NAMESPACE}_project.project + ADD parentProjectPHID VARBINARY(64); + +ALTER TABLE {$NAMESPACE}_project.project + ADD hasWorkboard BOOL NOT NULL; + +ALTER TABLE {$NAMESPACE}_project.project + ADD hasMilestones BOOL NOT NULL; + +ALTER TABLE {$NAMESPACE}_project.project + ADD hasSubprojects BOOL NOT NULL; + +ALTER TABLE {$NAMESPACE}_project.project + ADD milestoneNumber INT UNSIGNED; + +ALTER TABLE {$NAMESPACE}_project.project + ADD UNIQUE KEY `key_milestone` (parentProjectPHID, milestoneNumber); diff --git a/resources/sql/autopatches/20151219.proj.11.subprojectphids.sql b/resources/sql/autopatches/20151219.proj.11.subprojectphids.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20151219.proj.11.subprojectphids.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_project.project + DROP subprojectPHIDs; diff --git a/src/applications/policy/__tests__/PhabricatorPolicyDataTestCase.php b/src/applications/policy/__tests__/PhabricatorPolicyDataTestCase.php --- a/src/applications/policy/__tests__/PhabricatorPolicyDataTestCase.php +++ b/src/applications/policy/__tests__/PhabricatorPolicyDataTestCase.php @@ -11,19 +11,11 @@ public function testProjectPolicyMembership() { $author = $this->generateNewTestUser(); - $proj_a = id(new PhabricatorProject()) + $proj_a = PhabricatorProject::initializeNewProject($author) ->setName('A') - ->setAuthorPHID($author->getPHID()) - ->setIcon(PhabricatorProject::DEFAULT_ICON) - ->setColor(PhabricatorProject::DEFAULT_COLOR) - ->setIsMembershipLocked(0) ->save(); - $proj_b = id(new PhabricatorProject()) + $proj_b = PhabricatorProject::initializeNewProject($author) ->setName('B') - ->setAuthorPHID($author->getPHID()) - ->setIcon(PhabricatorProject::DEFAULT_ICON) - ->setColor(PhabricatorProject::DEFAULT_COLOR) - ->setIsMembershipLocked(0) ->save(); $proj_a->setViewPolicy($proj_b->getPHID())->save(); diff --git a/src/applications/project/storage/PhabricatorProject.php b/src/applications/project/storage/PhabricatorProject.php --- a/src/applications/project/storage/PhabricatorProject.php +++ b/src/applications/project/storage/PhabricatorProject.php @@ -12,8 +12,7 @@ protected $name; protected $status = PhabricatorProjectStatus::STATUS_ACTIVE; protected $authorPHID; - protected $subprojectPHIDs = array(); - protected $phrictionSlug; + protected $primarySlug; protected $profileImagePHID; protected $icon; protected $color; @@ -24,6 +23,12 @@ protected $joinPolicy; protected $isMembershipLocked; + protected $parentProjectPHID; + protected $hasWorkboard; + protected $hasMilestones; + protected $hasSubprojects; + protected $milestoneNumber; + private $memberPHIDs = self::ATTACHABLE; private $watcherPHIDs = self::ATTACHABLE; private $sparseWatchers = self::ATTACHABLE; @@ -31,6 +36,7 @@ private $customFields = self::ATTACHABLE; private $profileImageFile = self::ATTACHABLE; private $slugs = self::ATTACHABLE; + private $parentProject = self::ATTACHABLE; const DEFAULT_ICON = 'fa-briefcase'; const DEFAULT_COLOR = 'blue'; @@ -59,7 +65,10 @@ ->setJoinPolicy($join_policy) ->setIsMembershipLocked(0) ->attachMemberPHIDs(array()) - ->attachSlugs(array()); + ->attachSlugs(array()) + ->setHasWorkboard(0) + ->setHasMilestones(0) + ->setHasSubprojects(0); } public function getCapabilities() { @@ -132,24 +141,21 @@ protected function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, - self::CONFIG_SERIALIZATION => array( - 'subprojectPHIDs' => self::SERIALIZATION_JSON, - ), self::CONFIG_COLUMN_SCHEMA => array( 'name' => 'sort128', 'status' => 'text32', - 'phrictionSlug' => 'text128?', + 'primarySlug' => 'text128?', 'isMembershipLocked' => 'bool', 'profileImagePHID' => 'phid?', 'icon' => 'text32', 'color' => 'text32', 'mailKey' => 'bytes20', - - // T6203/NULLABILITY - // These are definitely wrong and should always exist. - 'editPolicy' => 'policy?', - 'viewPolicy' => 'policy?', - 'joinPolicy' => 'policy?', + 'joinPolicy' => 'policy', + 'parentProjectPHID' => 'phid?', + 'hasWorkboard' => 'bool', + 'hasMilestones' => 'bool', + 'hasSubprojects' => 'bool', + 'milestoneNumber' => 'uint32?', ), self::CONFIG_KEY_SCHEMA => array( 'key_phid' => null, @@ -163,14 +169,18 @@ 'key_color' => array( 'columns' => array('color'), ), - 'phrictionSlug' => array( - 'columns' => array('phrictionSlug'), - 'unique' => true, - ), 'name' => array( 'columns' => array('name'), 'unique' => true, ), + 'key_milestone' => array( + 'columns' => array('parentProjectPHID', 'milestoneNumber'), + 'unique' => true, + ), + 'key_primaryslug' => array( + 'columns' => array('primarySlug'), + 'unique' => true, + ), ), ) + parent::getConfiguration(); } @@ -189,19 +199,6 @@ return $this->assertAttached($this->memberPHIDs); } - public function setPrimarySlug($slug) { - $this->phrictionSlug = $slug.'/'; - return $this; - } - - // TODO - once we sever project => phriction automagicalness, - // migrate getPhrictionSlug to have no trailing slash and be called - // getPrimarySlug - public function getPrimarySlug() { - $slug = $this->getPhrictionSlug(); - return rtrim($slug, '/'); - } - public function isArchived() { return ($this->getStatus() == PhabricatorProjectStatus::STATUS_ARCHIVED); } @@ -313,6 +310,19 @@ $this->saveTransaction(); } + public function isMilestone() { + return ($this->getMilestoneNumber() !== null); + } + + public function getParentProject() { + return $this->assertAttached($this->parentProject); + } + + public function attachParentProject(PhabricatorProject $project) { + $this->parentProject = $project; + return $this; + } + /* -( PhabricatorSubscribableInterface )----------------------------------- */