Add transaction-oriented editing to projects
Summary: - Make some editing operations transaction-oriented, like Maniphest. (This seems to be a good model, particularly for extensibility.) I'll move the rest of the editing operations to transactions in future diffs. - Make transaction-oriented operations publish feed stories. Test Plan: - Created a new project. - Edited an existing project. - Created a new project via quick create flow from Maniphest. - Verified feed stories publish correctly. Reviewers: btrahan, jungejason Reviewed By: btrahan CC: aran, epriestley Maniphest Tasks: T681 Differential Revision: https://secure.phabricator.com/D1477
This commit is contained in:
11
resources/sql/patches/100.projectxaction.sql
Normal file
11
resources/sql/patches/100.projectxaction.sql
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
CREATE TABLE phabricator_project.project_transaction (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
projectID INT UNSIGNED NOT NULL,
|
||||||
|
authorPHID VARCHAR(64) BINARY NOT NULL,
|
||||||
|
transactionType VARCHAR(32) NOT NULL,
|
||||||
|
oldValue LONGBLOB NOT NULL,
|
||||||
|
newValue LONGBLOB NOT NULL,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
KEY (projectID)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
@@ -485,6 +485,7 @@ phutil_register_library_map(array(
|
|||||||
'PhabricatorFeedStoryDifferential' => 'applications/feed/story/differential',
|
'PhabricatorFeedStoryDifferential' => 'applications/feed/story/differential',
|
||||||
'PhabricatorFeedStoryManiphest' => 'applications/feed/story/maniphest',
|
'PhabricatorFeedStoryManiphest' => 'applications/feed/story/maniphest',
|
||||||
'PhabricatorFeedStoryPhriction' => 'applications/feed/story/phriction',
|
'PhabricatorFeedStoryPhriction' => 'applications/feed/story/phriction',
|
||||||
|
'PhabricatorFeedStoryProject' => 'applications/feed/story/project',
|
||||||
'PhabricatorFeedStoryPublisher' => 'applications/feed/publisher',
|
'PhabricatorFeedStoryPublisher' => 'applications/feed/publisher',
|
||||||
'PhabricatorFeedStoryReference' => 'applications/feed/storage/storyreference',
|
'PhabricatorFeedStoryReference' => 'applications/feed/storage/storyreference',
|
||||||
'PhabricatorFeedStoryStatus' => 'applications/feed/story/status',
|
'PhabricatorFeedStoryStatus' => 'applications/feed/story/status',
|
||||||
@@ -611,6 +612,7 @@ phutil_register_library_map(array(
|
|||||||
'PhabricatorProject' => 'applications/project/storage/project',
|
'PhabricatorProject' => 'applications/project/storage/project',
|
||||||
'PhabricatorProjectAffiliation' => 'applications/project/storage/affiliation',
|
'PhabricatorProjectAffiliation' => 'applications/project/storage/affiliation',
|
||||||
'PhabricatorProjectAffiliationEditController' => 'applications/project/controller/editaffiliation',
|
'PhabricatorProjectAffiliationEditController' => 'applications/project/controller/editaffiliation',
|
||||||
|
'PhabricatorProjectConstants' => 'applications/project/constants/base',
|
||||||
'PhabricatorProjectController' => 'applications/project/controller/base',
|
'PhabricatorProjectController' => 'applications/project/controller/base',
|
||||||
'PhabricatorProjectCreateController' => 'applications/project/controller/create',
|
'PhabricatorProjectCreateController' => 'applications/project/controller/create',
|
||||||
'PhabricatorProjectDAO' => 'applications/project/storage/base',
|
'PhabricatorProjectDAO' => 'applications/project/storage/base',
|
||||||
@@ -623,6 +625,8 @@ phutil_register_library_map(array(
|
|||||||
'PhabricatorProjectQuery' => 'applications/project/query/project',
|
'PhabricatorProjectQuery' => 'applications/project/query/project',
|
||||||
'PhabricatorProjectStatus' => 'applications/project/constants/status',
|
'PhabricatorProjectStatus' => 'applications/project/constants/status',
|
||||||
'PhabricatorProjectSubproject' => 'applications/project/storage/subproject',
|
'PhabricatorProjectSubproject' => 'applications/project/storage/subproject',
|
||||||
|
'PhabricatorProjectTransaction' => 'applications/project/storage/transaction',
|
||||||
|
'PhabricatorProjectTransactionType' => 'applications/project/constants/transaction',
|
||||||
'PhabricatorRedirectController' => 'applications/base/controller/redirect',
|
'PhabricatorRedirectController' => 'applications/base/controller/redirect',
|
||||||
'PhabricatorRefreshCSRFController' => 'applications/auth/controller/refresh',
|
'PhabricatorRefreshCSRFController' => 'applications/auth/controller/refresh',
|
||||||
'PhabricatorRemarkupRuleDifferential' => 'infrastructure/markup/remarkup/markuprule/differential',
|
'PhabricatorRemarkupRuleDifferential' => 'infrastructure/markup/remarkup/markuprule/differential',
|
||||||
@@ -1192,6 +1196,7 @@ phutil_register_library_map(array(
|
|||||||
'PhabricatorFeedStoryDifferential' => 'PhabricatorFeedStory',
|
'PhabricatorFeedStoryDifferential' => 'PhabricatorFeedStory',
|
||||||
'PhabricatorFeedStoryManiphest' => 'PhabricatorFeedStory',
|
'PhabricatorFeedStoryManiphest' => 'PhabricatorFeedStory',
|
||||||
'PhabricatorFeedStoryPhriction' => 'PhabricatorFeedStory',
|
'PhabricatorFeedStoryPhriction' => 'PhabricatorFeedStory',
|
||||||
|
'PhabricatorFeedStoryProject' => 'PhabricatorFeedStory',
|
||||||
'PhabricatorFeedStoryReference' => 'PhabricatorFeedDAO',
|
'PhabricatorFeedStoryReference' => 'PhabricatorFeedDAO',
|
||||||
'PhabricatorFeedStoryStatus' => 'PhabricatorFeedStory',
|
'PhabricatorFeedStoryStatus' => 'PhabricatorFeedStory',
|
||||||
'PhabricatorFeedStoryTypeConstants' => 'PhabricatorFeedConstants',
|
'PhabricatorFeedStoryTypeConstants' => 'PhabricatorFeedConstants',
|
||||||
@@ -1304,6 +1309,8 @@ phutil_register_library_map(array(
|
|||||||
'PhabricatorProjectProfileController' => 'PhabricatorProjectController',
|
'PhabricatorProjectProfileController' => 'PhabricatorProjectController',
|
||||||
'PhabricatorProjectProfileEditController' => 'PhabricatorProjectController',
|
'PhabricatorProjectProfileEditController' => 'PhabricatorProjectController',
|
||||||
'PhabricatorProjectSubproject' => 'PhabricatorProjectDAO',
|
'PhabricatorProjectSubproject' => 'PhabricatorProjectDAO',
|
||||||
|
'PhabricatorProjectTransaction' => 'PhabricatorProjectDAO',
|
||||||
|
'PhabricatorProjectTransactionType' => 'PhabricatorProjectConstants',
|
||||||
'PhabricatorRedirectController' => 'PhabricatorController',
|
'PhabricatorRedirectController' => 'PhabricatorController',
|
||||||
'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController',
|
'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController',
|
||||||
'PhabricatorRemarkupRuleDifferential' => 'PhabricatorRemarkupRuleObjectName',
|
'PhabricatorRemarkupRuleDifferential' => 'PhabricatorRemarkupRuleObjectName',
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2011 Facebook, Inc.
|
* Copyright 2012 Facebook, Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -19,10 +19,11 @@
|
|||||||
final class PhabricatorFeedStoryTypeConstants
|
final class PhabricatorFeedStoryTypeConstants
|
||||||
extends PhabricatorFeedConstants {
|
extends PhabricatorFeedConstants {
|
||||||
|
|
||||||
const STORY_UNKNOWN = 'PhabricatorFeedStoryUnknown';
|
const STORY_UNKNOWN = 'PhabricatorFeedStoryUnknown';
|
||||||
const STORY_STATUS = 'PhabricatorFeedStoryStatus';
|
const STORY_STATUS = 'PhabricatorFeedStoryStatus';
|
||||||
const STORY_DIFFERENTIAL = 'PhabricatorFeedStoryDifferential';
|
const STORY_DIFFERENTIAL = 'PhabricatorFeedStoryDifferential';
|
||||||
const STORY_PHRICTION = 'PhabricatorFeedStoryPhriction';
|
const STORY_PHRICTION = 'PhabricatorFeedStoryPhriction';
|
||||||
const STORY_MANIPHEST = 'PhabricatorFeedStoryManiphest';
|
const STORY_MANIPHEST = 'PhabricatorFeedStoryManiphest';
|
||||||
|
const STORY_PROJECT = 'PhabricatorFeedStoryProject';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2012 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PhabricatorFeedStoryProject extends PhabricatorFeedStory {
|
||||||
|
|
||||||
|
public function getRequiredHandlePHIDs() {
|
||||||
|
return array(
|
||||||
|
$this->getStoryData()->getAuthorPHID(),
|
||||||
|
$this->getStoryData()->getValue('projectPHID'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequiredObjectPHIDs() {
|
||||||
|
return array(
|
||||||
|
$this->getStoryData()->getAuthorPHID(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderView() {
|
||||||
|
$data = $this->getStoryData();
|
||||||
|
|
||||||
|
$view = new PhabricatorFeedStoryView();
|
||||||
|
|
||||||
|
$type = $data->getValue('type');
|
||||||
|
$old = $data->getValue('old');
|
||||||
|
$new = $data->getValue('new');
|
||||||
|
$proj = $this->getHandle($data->getValue('projectPHID'));
|
||||||
|
$auth = $this->getHandle($data->getAuthorPHID());
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case PhabricatorProjectTransactionType::TYPE_NAME:
|
||||||
|
if (strlen($old)) {
|
||||||
|
$action = 'renamed project '.
|
||||||
|
'<strong>'.$proj->renderLink().'</strong>'.
|
||||||
|
' from '.
|
||||||
|
'<strong>'.phutil_escape_html($old).'</strong>'.
|
||||||
|
' to '.
|
||||||
|
'<strong>'.phutil_escape_html($new).'</strong>.';
|
||||||
|
} else {
|
||||||
|
$action = 'created project '.
|
||||||
|
'<strong>'.$proj->renderLink().'</strong>'.
|
||||||
|
' (as '.
|
||||||
|
'<strong>'.phutil_escape_html($new).'</strong>).';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$action = 'updated project <strong>'.$proj->renderLink().'</strong>';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$view->setTitle('<strong>'.$auth->renderLink().'</strong> '.$action);
|
||||||
|
$view->setOneLineStory(true);
|
||||||
|
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
16
src/applications/feed/story/project/__init__.php
Normal file
16
src/applications/feed/story/project/__init__.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'applications/feed/story/base');
|
||||||
|
phutil_require_module('phabricator', 'applications/feed/view/story');
|
||||||
|
phutil_require_module('phabricator', 'applications/project/constants/transaction');
|
||||||
|
|
||||||
|
phutil_require_module('phutil', 'markup');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('PhabricatorFeedStoryProject.php');
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2012 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class PhabricatorProjectConstants {
|
||||||
|
|
||||||
|
}
|
||||||
10
src/applications/project/constants/base/__init__.php
Normal file
10
src/applications/project/constants/base/__init__.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('PhabricatorProjectConstants.php');
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2012 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
final class PhabricatorProjectTransactionType
|
||||||
|
extends PhabricatorProjectConstants {
|
||||||
|
|
||||||
|
const TYPE_NAME = 'name';
|
||||||
|
const TYPE_MEMBERS = 'members';
|
||||||
|
|
||||||
|
}
|
||||||
12
src/applications/project/constants/transaction/__init__.php
Normal file
12
src/applications/project/constants/transaction/__init__.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'applications/project/constants/base');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('PhabricatorProjectTransactionType.php');
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2011 Facebook, Inc.
|
* Copyright 2012 Facebook, Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -34,10 +34,16 @@ class PhabricatorProjectCreateController
|
|||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
$xactions = array();
|
||||||
|
$xaction = new PhabricatorProjectTransaction();
|
||||||
|
$xaction->setTransactionType(
|
||||||
|
PhabricatorProjectTransactionType::TYPE_NAME);
|
||||||
|
$xaction->setNewValue($request->getStr('name'));
|
||||||
|
$xactions[] = $xaction;
|
||||||
|
|
||||||
$editor = new PhabricatorProjectEditor($project);
|
$editor = new PhabricatorProjectEditor($project);
|
||||||
$editor->setUser($user);
|
$editor->setUser($user);
|
||||||
$editor->setName($request->getStr('name'));
|
$editor->applyTransactions($xactions);
|
||||||
$editor->save();
|
|
||||||
} catch (PhabricatorProjectNameCollisionException $ex) {
|
} catch (PhabricatorProjectNameCollisionException $ex) {
|
||||||
$e_name = 'Not Unique';
|
$e_name = 'Not Unique';
|
||||||
$errors[] = $ex->getMessage();
|
$errors[] = $ex->getMessage();
|
||||||
|
|||||||
@@ -10,11 +10,13 @@ phutil_require_module('phabricator', 'aphront/response/ajax');
|
|||||||
phutil_require_module('phabricator', 'aphront/response/dialog');
|
phutil_require_module('phabricator', 'aphront/response/dialog');
|
||||||
phutil_require_module('phabricator', 'aphront/response/redirect');
|
phutil_require_module('phabricator', 'aphront/response/redirect');
|
||||||
phutil_require_module('phabricator', 'applications/project/constants/status');
|
phutil_require_module('phabricator', 'applications/project/constants/status');
|
||||||
|
phutil_require_module('phabricator', 'applications/project/constants/transaction');
|
||||||
phutil_require_module('phabricator', 'applications/project/controller/base');
|
phutil_require_module('phabricator', 'applications/project/controller/base');
|
||||||
phutil_require_module('phabricator', 'applications/project/editor/project');
|
phutil_require_module('phabricator', 'applications/project/editor/project');
|
||||||
phutil_require_module('phabricator', 'applications/project/storage/affiliation');
|
phutil_require_module('phabricator', 'applications/project/storage/affiliation');
|
||||||
phutil_require_module('phabricator', 'applications/project/storage/profile');
|
phutil_require_module('phabricator', 'applications/project/storage/profile');
|
||||||
phutil_require_module('phabricator', 'applications/project/storage/project');
|
phutil_require_module('phabricator', 'applications/project/storage/project');
|
||||||
|
phutil_require_module('phabricator', 'applications/project/storage/transaction');
|
||||||
phutil_require_module('phabricator', 'view/dialog');
|
phutil_require_module('phabricator', 'view/dialog');
|
||||||
phutil_require_module('phabricator', 'view/form/base');
|
phutil_require_module('phabricator', 'view/form/base');
|
||||||
phutil_require_module('phabricator', 'view/form/control/submit');
|
phutil_require_module('phabricator', 'view/form/control/submit');
|
||||||
|
|||||||
@@ -58,10 +58,16 @@ class PhabricatorProjectProfileEditController
|
|||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
$xactions = array();
|
||||||
|
$xaction = new PhabricatorProjectTransaction();
|
||||||
|
$xaction->setTransactionType(
|
||||||
|
PhabricatorProjectTransactionType::TYPE_NAME);
|
||||||
|
$xaction->setNewValue($request->getStr('name'));
|
||||||
|
$xactions[] = $xaction;
|
||||||
|
|
||||||
$editor = new PhabricatorProjectEditor($project);
|
$editor = new PhabricatorProjectEditor($project);
|
||||||
$editor->setUser($user);
|
$editor->setUser($user);
|
||||||
$editor->setName($request->getStr('name'));
|
$editor->applyTransactions($xactions);
|
||||||
$editor->save();
|
|
||||||
} catch (PhabricatorProjectNameCollisionException $ex) {
|
} catch (PhabricatorProjectNameCollisionException $ex) {
|
||||||
$e_name = 'Not Unique';
|
$e_name = 'Not Unique';
|
||||||
$errors[] = $ex->getMessage();
|
$errors[] = $ex->getMessage();
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ phutil_require_module('phabricator', 'applications/files/storage/file');
|
|||||||
phutil_require_module('phabricator', 'applications/files/transform');
|
phutil_require_module('phabricator', 'applications/files/transform');
|
||||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||||
phutil_require_module('phabricator', 'applications/project/constants/status');
|
phutil_require_module('phabricator', 'applications/project/constants/status');
|
||||||
|
phutil_require_module('phabricator', 'applications/project/constants/transaction');
|
||||||
phutil_require_module('phabricator', 'applications/project/controller/base');
|
phutil_require_module('phabricator', 'applications/project/controller/base');
|
||||||
phutil_require_module('phabricator', 'applications/project/editor/project');
|
phutil_require_module('phabricator', 'applications/project/editor/project');
|
||||||
phutil_require_module('phabricator', 'applications/project/storage/affiliation');
|
phutil_require_module('phabricator', 'applications/project/storage/affiliation');
|
||||||
phutil_require_module('phabricator', 'applications/project/storage/profile');
|
phutil_require_module('phabricator', 'applications/project/storage/profile');
|
||||||
phutil_require_module('phabricator', 'applications/project/storage/project');
|
phutil_require_module('phabricator', 'applications/project/storage/project');
|
||||||
|
phutil_require_module('phabricator', 'applications/project/storage/transaction');
|
||||||
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
||||||
phutil_require_module('phabricator', 'infrastructure/javelin/api');
|
phutil_require_module('phabricator', 'infrastructure/javelin/api');
|
||||||
phutil_require_module('phabricator', 'infrastructure/javelin/markup');
|
phutil_require_module('phabricator', 'infrastructure/javelin/markup');
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2011 Facebook, Inc.
|
* Copyright 2012 Facebook, Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -20,45 +20,64 @@ final class PhabricatorProjectEditor {
|
|||||||
|
|
||||||
private $project;
|
private $project;
|
||||||
private $user;
|
private $user;
|
||||||
|
|
||||||
private $projectName;
|
private $projectName;
|
||||||
|
|
||||||
|
private $addAffiliations;
|
||||||
|
private $remAffiliations;
|
||||||
|
|
||||||
public function __construct(PhabricatorProject $project) {
|
public function __construct(PhabricatorProject $project) {
|
||||||
$this->project = $project;
|
$this->project = $project;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setName($name) {
|
|
||||||
$this->projectName = $name;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setUser(PhabricatorUser $user) {
|
public function setUser(PhabricatorUser $user) {
|
||||||
$this->user = $user;
|
$this->user = $user;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save() {
|
public function applyTransactions(array $transactions) {
|
||||||
if (!$this->user) {
|
if (!$this->user) {
|
||||||
throw new Exception('Call setUser() before save()!');
|
throw new Exception('Call setUser() before save()!');
|
||||||
}
|
}
|
||||||
|
$user = $this->user;
|
||||||
|
|
||||||
$project = $this->project;
|
$project = $this->project;
|
||||||
|
|
||||||
$is_new = !$project->getID();
|
$is_new = !$project->getID();
|
||||||
|
|
||||||
if ($is_new) {
|
if ($is_new) {
|
||||||
$project->setAuthorPHID($this->user->getPHID());
|
$project->setAuthorPHID($user->getPHID());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($this->projectName !== null) &&
|
foreach ($transactions as $xaction) {
|
||||||
($this->projectName !== $project->getName())) {
|
$type = $xaction->getTransactionType();
|
||||||
$project->setName($this->projectName);
|
|
||||||
$project->setPhrictionSlug($this->projectName);
|
$this->setTransactionOldValue($project, $xaction);
|
||||||
$this->validateName($project);
|
$this->applyTransactionEffect($project, $xaction);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$project->save();
|
$project->save();
|
||||||
|
|
||||||
|
foreach ($transactions as $xaction) {
|
||||||
|
$xaction->setAuthorPHID($user->getPHID());
|
||||||
|
$xaction->setProjectID($project->getID());
|
||||||
|
$xaction->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->remAffiliations as $affil) {
|
||||||
|
$affil->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->addAffiliations as $affil) {
|
||||||
|
$affil->setProjectPHID($project->getPHID());
|
||||||
|
$affil->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($transactions as $xaction) {
|
||||||
|
$this->publishTransactionStory($project, $xaction);
|
||||||
|
}
|
||||||
|
|
||||||
} catch (AphrontQueryDuplicateKeyException $ex) {
|
} catch (AphrontQueryDuplicateKeyException $ex) {
|
||||||
// We already validated the slug, but might race. Try again to see if
|
// We already validated the slug, but might race. Try again to see if
|
||||||
// that's the issue. If it is, we'll throw a more specific exception. If
|
// that's the issue. If it is, we'll throw a more specific exception. If
|
||||||
@@ -100,4 +119,97 @@ final class PhabricatorProjectEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function setTransactionOldValue(
|
||||||
|
PhabricatorProject $project,
|
||||||
|
PhabricatorProjectTransaction $xaction) {
|
||||||
|
|
||||||
|
$type = $xaction->getTransactionType();
|
||||||
|
switch ($type) {
|
||||||
|
case PhabricatorProjectTransactionType::TYPE_NAME:
|
||||||
|
$xaction->setOldValue($project->getName());
|
||||||
|
break;
|
||||||
|
case PhabricatorProjectTransactionType::TYPE_MEMBERS:
|
||||||
|
$affils = $project->loadAffiliations();
|
||||||
|
$project->attachAffiliations($affils);
|
||||||
|
|
||||||
|
$old_value = mpull($affils, 'getUserPHID');
|
||||||
|
$old_value = array_values($old_value);
|
||||||
|
$xaction->setOldValue($affils);
|
||||||
|
|
||||||
|
$new_value = $xaction->getNewValue();
|
||||||
|
$new_value = array_filter($new_value);
|
||||||
|
$new_value = array_unique($new_value);
|
||||||
|
$new_value = array_values($new_value);
|
||||||
|
$xaction->setNewValue($new_value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Unknown transaction type '{$type}'!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyTransactionEffect(
|
||||||
|
PhabricatorProject $project,
|
||||||
|
PhabricatorProjectTransaction $xaction) {
|
||||||
|
|
||||||
|
$type = $xaction->getTransactionType();
|
||||||
|
switch ($type) {
|
||||||
|
case PhabricatorProjectTransactionType::TYPE_NAME:
|
||||||
|
$project->setName($xaction->getNewValue());
|
||||||
|
$project->setPhrictionSlug($xaction->getNewValue());
|
||||||
|
$this->validateName($project);
|
||||||
|
break;
|
||||||
|
case PhabricatorProjectTransactionType::TYPE_MEMBERS:
|
||||||
|
$old = array_fill_keys($xaction->getOldValue(), true);
|
||||||
|
$new = array_fill_keys($xaction->getNewValue(), true);
|
||||||
|
|
||||||
|
$add = array();
|
||||||
|
$rem = array();
|
||||||
|
|
||||||
|
foreach ($project->getAffiliations() as $affil) {
|
||||||
|
if (empty($new[$affil->getUserPHID()])) {
|
||||||
|
$rem[] = $affil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($new as $phid => $ignored) {
|
||||||
|
if (empty($old[$phid])) {
|
||||||
|
$affil = new PhabricatorProjectAffiliation();
|
||||||
|
$affil->setUserPHID($phid);
|
||||||
|
$add[] = $affil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addAffiliations = $add;
|
||||||
|
$this->remAffiliations = $rem;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Unknown transaction type '{$type}'!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function publishTransactionStory(
|
||||||
|
PhabricatorProject $project,
|
||||||
|
PhabricatorProjectTransaction $xaction) {
|
||||||
|
|
||||||
|
$related_phids = array(
|
||||||
|
$project->getPHID(),
|
||||||
|
$xaction->getAuthorPHID(),
|
||||||
|
);
|
||||||
|
|
||||||
|
id(new PhabricatorFeedStoryPublisher())
|
||||||
|
->setStoryType(PhabricatorFeedStoryTypeConstants::STORY_PROJECT)
|
||||||
|
->setStoryData(
|
||||||
|
array(
|
||||||
|
'projectPHID' => $project->getPHID(),
|
||||||
|
'transactionID' => $xaction->getID(),
|
||||||
|
'type' => $xaction->getTransactionType(),
|
||||||
|
'old' => $xaction->getOldValue(),
|
||||||
|
'new' => $xaction->getNewValue(),
|
||||||
|
))
|
||||||
|
->setStoryTime(time())
|
||||||
|
->setStoryAuthorPHID($xaction->getAuthorPHID())
|
||||||
|
->setRelatedPHIDs($related_phids)
|
||||||
|
->publish();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,11 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'applications/feed/constants/story');
|
||||||
|
phutil_require_module('phabricator', 'applications/feed/publisher');
|
||||||
|
phutil_require_module('phabricator', 'applications/project/constants/transaction');
|
||||||
phutil_require_module('phabricator', 'applications/project/exception/namecollison');
|
phutil_require_module('phabricator', 'applications/project/exception/namecollison');
|
||||||
|
phutil_require_module('phabricator', 'applications/project/storage/affiliation');
|
||||||
phutil_require_module('phabricator', 'applications/project/storage/project');
|
phutil_require_module('phabricator', 'applications/project/storage/project');
|
||||||
|
|
||||||
phutil_require_module('phutil', 'utils');
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2012 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group project
|
||||||
|
*/
|
||||||
|
class PhabricatorProjectTransaction extends PhabricatorProjectDAO {
|
||||||
|
|
||||||
|
protected $projectID;
|
||||||
|
protected $authorPHID;
|
||||||
|
protected $transactionType;
|
||||||
|
protected $oldValue;
|
||||||
|
protected $newValue;
|
||||||
|
|
||||||
|
public function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_SERIALIZATION => array(
|
||||||
|
'oldValue' => self::SERIALIZATION_JSON,
|
||||||
|
'newValue' => self::SERIALIZATION_JSON,
|
||||||
|
),
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
12
src/applications/project/storage/transaction/__init__.php
Normal file
12
src/applications/project/storage/transaction/__init__.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'applications/project/storage/base');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('PhabricatorProjectTransaction.php');
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2011 Facebook, Inc.
|
* Copyright 2012 Facebook, Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
Reference in New Issue
Block a user