mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-14 19:02:41 +01:00
8a3b1b9730
Summary: Ref T4029. this diff makes the pertinent database changes AND adds the migration script. This is important to get the data backend straightened away before we fully ship T4029. Next diff will expose the edit controls for these policies and whatever else work is needed to get that part done right. Test Plan: made sure the lone project page on my wiki had a project with restrictive view policy. Post migration verified correct policy applied to this lone project page AND most open policy applied to the others Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin, epriestley Maniphest Tasks: T4029 Differential Revision: https://secure.phabricator.com/D10814
254 lines
6.4 KiB
PHP
254 lines
6.4 KiB
PHP
<?php
|
|
|
|
final class PhrictionDocument extends PhrictionDAO
|
|
implements
|
|
PhabricatorPolicyInterface,
|
|
PhabricatorSubscribableInterface,
|
|
PhabricatorFlaggableInterface,
|
|
PhabricatorTokenReceiverInterface,
|
|
PhabricatorDestructibleInterface {
|
|
|
|
protected $slug;
|
|
protected $depth;
|
|
protected $contentID;
|
|
protected $status;
|
|
protected $mailKey;
|
|
protected $viewPolicy;
|
|
protected $editPolicy;
|
|
|
|
private $contentObject = self::ATTACHABLE;
|
|
private $ancestors = array();
|
|
|
|
// TODO: This should be `self::ATTACHABLE`, but there are still a lot of call
|
|
// sites which load PhrictionDocuments directly.
|
|
private $project = null;
|
|
|
|
public function getConfiguration() {
|
|
return array(
|
|
self::CONFIG_AUX_PHID => true,
|
|
self::CONFIG_TIMESTAMPS => false,
|
|
self::CONFIG_COLUMN_SCHEMA => array(
|
|
'slug' => 'sort128',
|
|
'depth' => 'uint32',
|
|
'contentID' => 'id?',
|
|
'status' => 'uint32',
|
|
'mailKey' => 'bytes20',
|
|
),
|
|
self::CONFIG_KEY_SCHEMA => array(
|
|
'key_phid' => null,
|
|
'phid' => array(
|
|
'columns' => array('phid'),
|
|
'unique' => true,
|
|
),
|
|
'slug' => array(
|
|
'columns' => array('slug'),
|
|
'unique' => true,
|
|
),
|
|
'depth' => array(
|
|
'columns' => array('depth', 'slug'),
|
|
'unique' => true,
|
|
),
|
|
),
|
|
) + parent::getConfiguration();
|
|
}
|
|
|
|
public function generatePHID() {
|
|
return PhabricatorPHID::generateNewPHID(
|
|
PhrictionDocumentPHIDType::TYPECONST);
|
|
}
|
|
|
|
public static function initializeNewDocument(PhabricatorUser $actor, $slug) {
|
|
$document = new PhrictionDocument();
|
|
$document->setSlug($slug);
|
|
|
|
$content = new PhrictionContent();
|
|
$content->setSlug($slug);
|
|
|
|
$default_title = PhabricatorSlug::getDefaultTitle($slug);
|
|
$content->setTitle($default_title);
|
|
$document->attachContent($content);
|
|
|
|
$default_view_policy = PhabricatorPolicies::getMostOpenPolicy();
|
|
$document->setViewPolicy($default_view_policy);
|
|
$document->setEditPolicy(PhabricatorPolicies::POLICY_USER);
|
|
|
|
return $document;
|
|
}
|
|
|
|
public function save() {
|
|
if (!$this->getMailKey()) {
|
|
$this->setMailKey(Filesystem::readRandomCharacters(20));
|
|
}
|
|
return parent::save();
|
|
}
|
|
|
|
public static function getSlugURI($slug, $type = 'document') {
|
|
static $types = array(
|
|
'document' => '/w/',
|
|
'history' => '/phriction/history/',
|
|
);
|
|
|
|
if (empty($types[$type])) {
|
|
throw new Exception("Unknown URI type '{$type}'!");
|
|
}
|
|
|
|
$prefix = $types[$type];
|
|
|
|
if ($slug == '/') {
|
|
return $prefix;
|
|
} else {
|
|
// NOTE: The effect here is to escape non-latin characters, since modern
|
|
// browsers deal with escaped UTF8 characters in a reasonable way (showing
|
|
// the user a readable URI) but older programs may not.
|
|
$slug = phutil_escape_uri($slug);
|
|
return $prefix.$slug;
|
|
}
|
|
}
|
|
|
|
public function setSlug($slug) {
|
|
$this->slug = PhabricatorSlug::normalize($slug);
|
|
$this->depth = PhabricatorSlug::getDepth($slug);
|
|
return $this;
|
|
}
|
|
|
|
public function attachContent(PhrictionContent $content) {
|
|
$this->contentObject = $content;
|
|
return $this;
|
|
}
|
|
|
|
public function getContent() {
|
|
return $this->assertAttached($this->contentObject);
|
|
}
|
|
|
|
public function getProject() {
|
|
return $this->assertAttached($this->project);
|
|
}
|
|
|
|
public function attachProject(PhabricatorProject $project = null) {
|
|
$this->project = $project;
|
|
return $this;
|
|
}
|
|
|
|
public function hasProject() {
|
|
return (bool)$this->getProject();
|
|
}
|
|
|
|
public function getAncestors() {
|
|
return $this->ancestors;
|
|
}
|
|
|
|
public function getAncestor($slug) {
|
|
return $this->assertAttachedKey($this->ancestors, $slug);
|
|
}
|
|
|
|
public function attachAncestor($slug, $ancestor) {
|
|
$this->ancestors[$slug] = $ancestor;
|
|
return $this;
|
|
}
|
|
|
|
public static function isProjectSlug($slug) {
|
|
$slug = PhabricatorSlug::normalize($slug);
|
|
$prefix = 'projects/';
|
|
if ($slug == $prefix) {
|
|
// The 'projects/' document is not itself a project slug.
|
|
return false;
|
|
}
|
|
return !strncmp($slug, $prefix, strlen($prefix));
|
|
}
|
|
|
|
public static function getProjectSlugIdentifier($slug) {
|
|
if (!self::isProjectSlug($slug)) {
|
|
throw new Exception("Slug '{$slug}' is not a project slug!");
|
|
}
|
|
|
|
$slug = PhabricatorSlug::normalize($slug);
|
|
$parts = explode('/', $slug);
|
|
return $parts[1].'/';
|
|
}
|
|
|
|
|
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
|
|
|
|
|
public function getCapabilities() {
|
|
return array(
|
|
PhabricatorPolicyCapability::CAN_VIEW,
|
|
PhabricatorPolicyCapability::CAN_EDIT,
|
|
);
|
|
}
|
|
|
|
public function getPolicy($capability) {
|
|
switch ($capability) {
|
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
|
return $this->getViewPolicy();
|
|
case PhabricatorPolicyCapability::CAN_EDIT:
|
|
return $this->getEditPolicy();
|
|
}
|
|
}
|
|
|
|
public function hasAutomaticCapability($capability, PhabricatorUser $user) {
|
|
return false;
|
|
}
|
|
|
|
public function describeAutomaticCapability($capability) {
|
|
|
|
switch ($capability) {
|
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
|
return pht(
|
|
'To view a wiki document, you must also be able to view all '.
|
|
'of its parents.');
|
|
case PhabricatorPolicyCapability::CAN_EDIT:
|
|
return pht(
|
|
'To edit a wiki document, you must also be able to view all '.
|
|
'of its parents.');
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
/* -( PhabricatorSubscribableInterface )----------------------------------- */
|
|
|
|
|
|
public function isAutomaticallySubscribed($phid) {
|
|
return false;
|
|
}
|
|
|
|
public function shouldShowSubscribersProperty() {
|
|
return true;
|
|
}
|
|
|
|
public function shouldAllowSubscription($phid) {
|
|
return true;
|
|
}
|
|
|
|
|
|
/* -( PhabricatorTokenReceiverInterface )---------------------------------- */
|
|
|
|
|
|
public function getUsersToNotifyOfTokenGiven() {
|
|
return PhabricatorSubscribersQuery::loadSubscribersForPHID($this->phid);
|
|
}
|
|
|
|
|
|
/* -( PhabricatorDestructibleInterface )----------------------------------- */
|
|
|
|
|
|
public function destroyObjectPermanently(
|
|
PhabricatorDestructionEngine $engine) {
|
|
|
|
$this->openTransaction();
|
|
|
|
$this->delete();
|
|
|
|
$contents = id(new PhrictionContent())->loadAllWhere(
|
|
'documentID = %d',
|
|
$this->getID());
|
|
foreach ($contents as $content) {
|
|
$content->delete();
|
|
}
|
|
|
|
$this->saveTransaction();
|
|
}
|
|
|
|
}
|