2011-08-26 21:50:28 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/*
|
2012-04-10 23:18:20 +02:00
|
|
|
* Copyright 2012 Facebook, Inc.
|
2011-08-26 21:50:28 +02:00
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create or update Phriction documents.
|
2011-09-14 17:02:31 +02:00
|
|
|
*
|
|
|
|
* @group phriction
|
2011-08-26 21:50:28 +02:00
|
|
|
*/
|
|
|
|
final class PhrictionDocumentEditor {
|
|
|
|
|
|
|
|
private $document;
|
|
|
|
private $content;
|
|
|
|
|
|
|
|
private $user;
|
|
|
|
|
|
|
|
private $newTitle;
|
|
|
|
private $newContent;
|
|
|
|
private $description;
|
|
|
|
|
|
|
|
private function __construct() {
|
|
|
|
// <restricted>
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function newForSlug($slug) {
|
2012-04-10 23:18:20 +02:00
|
|
|
$slug = PhabricatorSlug::normalize($slug);
|
2011-08-26 21:50:28 +02:00
|
|
|
$document = id(new PhrictionDocument())->loadOneWhere(
|
|
|
|
'slug = %s',
|
|
|
|
$slug);
|
|
|
|
$content = null;
|
|
|
|
|
|
|
|
if ($document) {
|
|
|
|
$content = id(new PhrictionContent())->load($document->getContentID());
|
|
|
|
} else {
|
|
|
|
$document = new PhrictionDocument();
|
|
|
|
$document->setSlug($slug);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$content) {
|
2012-04-10 23:18:20 +02:00
|
|
|
$default_title = PhabricatorSlug::getDefaultTitle($slug);
|
2011-08-26 21:50:28 +02:00
|
|
|
$content = new PhrictionContent();
|
|
|
|
$content->setSlug($slug);
|
|
|
|
$content->setTitle($default_title);
|
Set default content to "" (empty string), not null, in PhrictionDocumentEditor
Summary: phriction.edit allows you to omit the content string, meaning "don't
edit content". If you're also creating the page, we currently break in a
terrible, horrible, no-good, very-bad way because 'content' can't be null.
Default to empty string instead so phriction.edit creates an empty page instead
of a broken mess.
Test Plan: Called phriction.edit on a new page with no content.
Reviewers: skrul, jungejason, nh, tuomaspelkonen, aran
Reviewed By: skrul
CC: aran, skrul
Differential Revision: 920
2011-09-12 20:11:45 +02:00
|
|
|
$content->setContent('');
|
2011-08-26 21:50:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$obj = new PhrictionDocumentEditor();
|
|
|
|
$obj->document = $document;
|
|
|
|
$obj->content = $content;
|
|
|
|
|
|
|
|
return $obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setUser(PhabricatorUser $user) {
|
|
|
|
$this->user = $user;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setTitle($title) {
|
|
|
|
$this->newTitle = $title;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setContent($content) {
|
|
|
|
$this->newContent = $content;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setDescription($description) {
|
|
|
|
$this->description = $description;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getDocument() {
|
|
|
|
return $this->document;
|
|
|
|
}
|
|
|
|
|
2011-12-17 18:19:08 +01:00
|
|
|
public function delete() {
|
|
|
|
if (!$this->user) {
|
|
|
|
throw new Exception("Call setUser() before deleting a document!");
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Should we do anything about deleting an already-deleted document?
|
|
|
|
// We currently allow it.
|
|
|
|
|
|
|
|
$document = $this->document;
|
|
|
|
$content = $this->content;
|
|
|
|
|
|
|
|
$new_content = $this->buildContentTemplate($document, $content);
|
|
|
|
|
|
|
|
$new_content->setChangeType(PhrictionChangeType::CHANGE_DELETE);
|
|
|
|
$new_content->setContent('');
|
|
|
|
|
|
|
|
return $this->updateDocument($document, $content, $new_content);
|
|
|
|
}
|
|
|
|
|
2011-08-26 21:50:28 +02:00
|
|
|
public function save() {
|
|
|
|
if (!$this->user) {
|
2011-12-17 18:19:08 +01:00
|
|
|
throw new Exception("Call setUser() before updating a document!");
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->newContent === '') {
|
|
|
|
// If this is an edit which deletes all the content, just treat it as
|
|
|
|
// a delete. NOTE: null means "don't change the content", not "delete
|
|
|
|
// the page"! Thus the strict type check.
|
|
|
|
return $this->delete();
|
2011-08-26 21:50:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$document = $this->document;
|
|
|
|
$content = $this->content;
|
|
|
|
|
2011-12-17 18:19:08 +01:00
|
|
|
$new_content = $this->buildContentTemplate($document, $content);
|
|
|
|
|
|
|
|
return $this->updateDocument($document, $content, $new_content);
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildContentTemplate(
|
|
|
|
PhrictionDocument $document,
|
|
|
|
PhrictionContent $content) {
|
|
|
|
|
2011-08-26 21:50:28 +02:00
|
|
|
$new_content = new PhrictionContent();
|
|
|
|
$new_content->setSlug($document->getSlug());
|
|
|
|
$new_content->setAuthorPHID($this->user->getPHID());
|
2011-12-17 18:19:08 +01:00
|
|
|
$new_content->setChangeType(PhrictionChangeType::CHANGE_EDIT);
|
2011-08-26 21:50:28 +02:00
|
|
|
|
|
|
|
$new_content->setTitle(
|
|
|
|
coalesce(
|
|
|
|
$this->newTitle,
|
|
|
|
$content->getTitle()));
|
|
|
|
|
|
|
|
$new_content->setContent(
|
|
|
|
coalesce(
|
|
|
|
$this->newContent,
|
|
|
|
$content->getContent()));
|
|
|
|
|
|
|
|
if (strlen($this->description)) {
|
|
|
|
$new_content->setDescription($this->description);
|
|
|
|
}
|
|
|
|
|
2011-12-17 18:19:08 +01:00
|
|
|
return $new_content;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function updateDocument($document, $content, $new_content) {
|
2011-08-26 21:50:28 +02:00
|
|
|
|
|
|
|
$is_new = false;
|
|
|
|
if (!$document->getID()) {
|
|
|
|
$is_new = true;
|
2011-12-17 18:19:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$new_content->setVersion($content->getVersion() + 1);
|
|
|
|
|
|
|
|
$change_type = $new_content->getChangeType();
|
|
|
|
switch ($change_type) {
|
|
|
|
case PhrictionChangeType::CHANGE_EDIT:
|
|
|
|
$doc_status = PhrictionDocumentStatus::STATUS_EXISTS;
|
|
|
|
$feed_action = $is_new
|
|
|
|
? PhrictionActionConstants::ACTION_CREATE
|
|
|
|
: PhrictionActionConstants::ACTION_EDIT;
|
|
|
|
break;
|
|
|
|
case PhrictionChangeType::CHANGE_DELETE:
|
|
|
|
$doc_status = PhrictionDocumentStatus::STATUS_DELETED;
|
|
|
|
$feed_action = PhrictionActionConstants::ACTION_DELETE;
|
|
|
|
if ($is_new) {
|
|
|
|
throw new Exception(
|
|
|
|
"You can not delete a document which doesn't exist yet!");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new Exception(
|
|
|
|
"Unsupported content change type '{$change_type}'!");
|
|
|
|
}
|
|
|
|
|
|
|
|
$document->setStatus($doc_status);
|
|
|
|
|
|
|
|
// TODO: This should be transactional.
|
|
|
|
|
|
|
|
if ($is_new) {
|
2011-08-26 21:50:28 +02:00
|
|
|
$document->save();
|
|
|
|
}
|
|
|
|
|
|
|
|
$new_content->setDocumentID($document->getID());
|
|
|
|
$new_content->save();
|
|
|
|
|
|
|
|
$document->setContentID($new_content->getID());
|
|
|
|
$document->save();
|
|
|
|
|
|
|
|
$document->attachContent($new_content);
|
|
|
|
PhabricatorSearchPhrictionIndexer::indexDocument($document);
|
|
|
|
|
Provide wiki pages for projects
Summary:
Provide tighter integration between Projects and Phriction. Partly, I have most
of a rewrite for the Projects homepage ready but it's not currently possible to
publish feed stories about a project so all the feeds are empty/boring. This
partly makes them more useful and partly just provides a tool integration point.
- When you create a project, all the wiki pages in projects/<project_name>/*
are associated with it.
- Publish updates to those pages as being related to the project so they'll
show up in project feeds.
- Show a project link on those pages.
This is very "convention over configuration" but I think it's the right
approach. We could provide some sort of, like, "@project=derp" tag to let you
associated arbitrary pages to projects later, but just letting you move pages is
probably far better.
Test Plan:
- Ran upgrade scripts against stupidly named projects ("der", " der", " der
", "der (2)", " der (2) (2)", etc). Ended up with uniquely named projects.
- Ran unit tests.
- Created /projects/ wiki documents and made sure they displayed correctly.
- Verified feed stories publish as project-related.
- Edited projects, including perfomring a name-colliding edit.
- Created projects, including performing a name-colliding create.
Reviewers: btrahan, jungejason
Reviewed By: btrahan
CC: aran, epriestley, btrahan
Maniphest Tasks: T681
Differential Revision: 1231
2011-12-17 20:58:55 +01:00
|
|
|
$project_phid = null;
|
|
|
|
$slug = $document->getSlug();
|
|
|
|
if (PhrictionDocument::isProjectSlug($slug)) {
|
|
|
|
$project = id(new PhabricatorProject())->loadOneWhere(
|
|
|
|
'phrictionSlug = %s',
|
|
|
|
PhrictionDocument::getProjectSlugIdentifier($slug));
|
|
|
|
if ($project) {
|
|
|
|
$project_phid = $project->getPHID();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$related_phids = array(
|
|
|
|
$document->getPHID(),
|
|
|
|
$this->user->getPHID(),
|
|
|
|
);
|
|
|
|
|
|
|
|
if ($project_phid) {
|
|
|
|
$related_phids[] = $project_phid;
|
|
|
|
}
|
|
|
|
|
2011-08-26 21:50:28 +02:00
|
|
|
id(new PhabricatorFeedStoryPublisher())
|
Provide wiki pages for projects
Summary:
Provide tighter integration between Projects and Phriction. Partly, I have most
of a rewrite for the Projects homepage ready but it's not currently possible to
publish feed stories about a project so all the feeds are empty/boring. This
partly makes them more useful and partly just provides a tool integration point.
- When you create a project, all the wiki pages in projects/<project_name>/*
are associated with it.
- Publish updates to those pages as being related to the project so they'll
show up in project feeds.
- Show a project link on those pages.
This is very "convention over configuration" but I think it's the right
approach. We could provide some sort of, like, "@project=derp" tag to let you
associated arbitrary pages to projects later, but just letting you move pages is
probably far better.
Test Plan:
- Ran upgrade scripts against stupidly named projects ("der", " der", " der
", "der (2)", " der (2) (2)", etc). Ended up with uniquely named projects.
- Ran unit tests.
- Created /projects/ wiki documents and made sure they displayed correctly.
- Verified feed stories publish as project-related.
- Edited projects, including perfomring a name-colliding edit.
- Created projects, including performing a name-colliding create.
Reviewers: btrahan, jungejason
Reviewed By: btrahan
CC: aran, epriestley, btrahan
Maniphest Tasks: T681
Differential Revision: 1231
2011-12-17 20:58:55 +01:00
|
|
|
->setRelatedPHIDs($related_phids)
|
2011-08-26 21:50:28 +02:00
|
|
|
->setStoryAuthorPHID($this->user->getPHID())
|
|
|
|
->setStoryTime(time())
|
|
|
|
->setStoryType(PhabricatorFeedStoryTypeConstants::STORY_PHRICTION)
|
|
|
|
->setStoryData(
|
|
|
|
array(
|
|
|
|
'phid' => $document->getPHID(),
|
2011-12-17 18:19:08 +01:00
|
|
|
'action' => $feed_action,
|
2011-08-26 21:50:28 +02:00
|
|
|
'content' => phutil_utf8_shorten($new_content->getContent(), 140),
|
Provide wiki pages for projects
Summary:
Provide tighter integration between Projects and Phriction. Partly, I have most
of a rewrite for the Projects homepage ready but it's not currently possible to
publish feed stories about a project so all the feeds are empty/boring. This
partly makes them more useful and partly just provides a tool integration point.
- When you create a project, all the wiki pages in projects/<project_name>/*
are associated with it.
- Publish updates to those pages as being related to the project so they'll
show up in project feeds.
- Show a project link on those pages.
This is very "convention over configuration" but I think it's the right
approach. We could provide some sort of, like, "@project=derp" tag to let you
associated arbitrary pages to projects later, but just letting you move pages is
probably far better.
Test Plan:
- Ran upgrade scripts against stupidly named projects ("der", " der", " der
", "der (2)", " der (2) (2)", etc). Ended up with uniquely named projects.
- Ran unit tests.
- Created /projects/ wiki documents and made sure they displayed correctly.
- Verified feed stories publish as project-related.
- Edited projects, including perfomring a name-colliding edit.
- Created projects, including performing a name-colliding create.
Reviewers: btrahan, jungejason
Reviewed By: btrahan
CC: aran, epriestley, btrahan
Maniphest Tasks: T681
Differential Revision: 1231
2011-12-17 20:58:55 +01:00
|
|
|
'project' => $project_phid,
|
2011-08-26 21:50:28 +02:00
|
|
|
))
|
|
|
|
->publish();
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|