diff --git a/resources/sql/patches/103.heraldedithistory.sql b/resources/sql/patches/103.heraldedithistory.sql new file mode 100644 index 0000000000..1b2f6f917c --- /dev/null +++ b/resources/sql/patches/103.heraldedithistory.sql @@ -0,0 +1,8 @@ +CREATE TABLE phabricator_herald.herald_ruleedit ( + id int unsigned not null auto_increment primary key, + ruleID int unsigned not null, + editorPHID varchar(64) BINARY not null, + dateCreated int unsigned not null, + dateModified int unsigned not null, + KEY (ruleID, dateCreated) +) ENGINE=InnoDB; diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 898bf3b6e7..b47eaecb47 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -332,14 +332,13 @@ celerity_register_resource_map(array( ), 0 => array( - 'uri' => '/res/b6096fdd/rsrc/js/javelin/lib/__tests__/URI.js', + 'uri' => '/res/14c48a9f/rsrc/js/javelin/lib/__tests__/behavior.js', 'type' => 'js', 'requires' => array( - 0 => 'javelin-uri', - 1 => 'javelin-php-serializer', + 0 => 'javelin-behavior', ), - 'disk' => '/rsrc/js/javelin/lib/__tests__/URI.js', + 'disk' => '/rsrc/js/javelin/lib/__tests__/behavior.js', ), 'javelin-behavior-aphront-basic-tokenizer' => array( diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 86abdb27d0..c2ea403def 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -358,6 +358,9 @@ phutil_register_library_map(array( 'HeraldRepetitionPolicyConfig' => 'applications/herald/config/repetitionpolicy', 'HeraldRule' => 'applications/herald/storage/rule', 'HeraldRuleController' => 'applications/herald/controller/rule', + 'HeraldRuleEdit' => 'applications/herald/storage/edithistory', + 'HeraldRuleEditHistoryController' => 'applications/herald/controller/edithistory', + 'HeraldRuleEditHistoryView' => 'applications/herald/view/edithistory', 'HeraldRuleListView' => 'applications/herald/view/rulelist', 'HeraldRuleTranscript' => 'applications/herald/storage/transcript/rule', 'HeraldRuleTypeConfig' => 'applications/herald/config/ruletype', @@ -1097,6 +1100,9 @@ phutil_register_library_map(array( 'HeraldNewController' => 'HeraldController', 'HeraldRule' => 'HeraldDAO', 'HeraldRuleController' => 'HeraldController', + 'HeraldRuleEdit' => 'HeraldDAO', + 'HeraldRuleEditHistoryController' => 'HeraldController', + 'HeraldRuleEditHistoryView' => 'AphrontView', 'HeraldRuleListView' => 'AphrontView', 'HeraldTestConsoleController' => 'HeraldController', 'HeraldTranscript' => 'HeraldDAO', diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php index f9cb0f574e..ec5d10359f 100644 --- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php @@ -283,6 +283,7 @@ class AphrontDefaultApplicationConfiguration ), 'new/(?:(?P[^/]+)/)?$' => 'HeraldNewController', 'rule/(?:(?P\d+)/)?$' => 'HeraldRuleController', + 'history/(?P\d+)/$' => 'HeraldRuleEditHistoryController', 'delete/(?P\d+)/$' => 'HeraldDeleteController', 'test/$' => 'HeraldTestConsoleController', 'all/' => array( diff --git a/src/applications/herald/controller/edithistory/HeraldRuleEditHistoryController.php b/src/applications/herald/controller/edithistory/HeraldRuleEditHistoryController.php new file mode 100644 index 0000000000..457c55130a --- /dev/null +++ b/src/applications/herald/controller/edithistory/HeraldRuleEditHistoryController.php @@ -0,0 +1,55 @@ +id = $data['id']; + } + + public function processRequest() { + $rule = id(new HeraldRule())->load($this->id); + if ($rule === null) { + return new Aphront404Response(); + } + + $edits = $rule->loadEdits(); + $rule->attachEdits($edits); + + $need_phids = mpull($edits, 'getEditorPHID'); + $handles = id(new PhabricatorObjectHandleData($need_phids)) + ->loadHandles(); + + $list_view = id(new HeraldRuleEditHistoryView()) + ->setRule($rule) + ->setHandles($handles) + ->setUser($this->getRequest()->getUser()); + + return $this->buildStandardPageResponse( + $list_view->render(), + array( + 'title' => 'Rule Edit History', + )); + } + + public function getFilter() { + return; + } +} diff --git a/src/applications/herald/controller/edithistory/__init__.php b/src/applications/herald/controller/edithistory/__init__.php new file mode 100644 index 0000000000..a85481c98a --- /dev/null +++ b/src/applications/herald/controller/edithistory/__init__.php @@ -0,0 +1,18 @@ +getPHID()); } + foreach ($rules as $rule) { + $edits = $rule->loadEdits(); + $rule->attachEdits($edits); + } + $need_phids = mpull($rules, 'getAuthorPHID'); $handles = id(new PhabricatorObjectHandleData($need_phids)) ->loadHandles(); @@ -72,7 +77,8 @@ class HeraldHomeController extends HeraldController { ->setHandles($handles) ->setMap($map) ->setAllowCreation(true) - ->setView($this->view); + ->setView($this->view) + ->setUser($user); $panel = $list_view->render(); diff --git a/src/applications/herald/controller/rule/HeraldRuleController.php b/src/applications/herald/controller/rule/HeraldRuleController.php index 2368c369c9..681965eadc 100644 --- a/src/applications/herald/controller/rule/HeraldRuleController.php +++ b/src/applications/herald/controller/rule/HeraldRuleController.php @@ -352,6 +352,7 @@ class HeraldRuleController extends HeraldController { $rule->save(); $rule->saveConditions($conditions); $rule->saveActions($actions); + $rule->saveEdit($request->getUser()->getPHID()); // $rule->saveTransaction(); } catch (AphrontQueryDuplicateKeyException $ex) { diff --git a/src/applications/herald/storage/edithistory/HeraldRuleEdit.php b/src/applications/herald/storage/edithistory/HeraldRuleEdit.php new file mode 100644 index 0000000000..7e1b8746c1 --- /dev/null +++ b/src/applications/herald/storage/edithistory/HeraldRuleEdit.php @@ -0,0 +1,24 @@ +actions; } + public function loadEdits() { + if (!$this->getID()) { + return array(); + } + $edits = id(new HeraldRuleEdit())->loadAllWhere( + 'ruleID = %d ORDER BY dateCreated DESC', + $this->getID()); + + return $edits; + } + + public function attachEdits(array $edits) { + $this->edits = $edits; + return $this; + } + + public function getEdits() { + if ($this->edits === null) { + throw new Exception("Attach edits before accessing them!"); + } + return $this->edits; + } + + public function saveEdit($editor_phid) { + $edit = new HeraldRuleEdit(); + $edit->setRuleID($this->getID()); + $edit->setEditorPHID($editor_phid); + $edit->save(); + } + public function saveConditions(array $conditions) { return $this->saveChildren( id(new HeraldCondition())->getTableName(), diff --git a/src/applications/herald/storage/rule/__init__.php b/src/applications/herald/storage/rule/__init__.php index 99772266f3..7078b9f324 100644 --- a/src/applications/herald/storage/rule/__init__.php +++ b/src/applications/herald/storage/rule/__init__.php @@ -9,6 +9,7 @@ phutil_require_module('phabricator', 'applications/herald/storage/action'); phutil_require_module('phabricator', 'applications/herald/storage/base'); phutil_require_module('phabricator', 'applications/herald/storage/condition'); +phutil_require_module('phabricator', 'applications/herald/storage/edithistory'); phutil_require_module('phabricator', 'storage/queryfx'); phutil_require_module('phutil', 'utils'); diff --git a/src/applications/herald/view/edithistory/HeraldRuleEditHistoryView.php b/src/applications/herald/view/edithistory/HeraldRuleEditHistoryView.php new file mode 100644 index 0000000000..a8cd516897 --- /dev/null +++ b/src/applications/herald/view/edithistory/HeraldRuleEditHistoryView.php @@ -0,0 +1,73 @@ +rule = $rule; + return $this; + } + + public function setHandles(array $handles) { + $this->handles = $handles; + return $this; + } + + public function setUser($user) { + $this->user = $user; + return $this; + } + + public function render() { + $rows = array(); + + foreach ($this->rule->getEdits() as $edit) { + $editor = $this->handles[$edit->getEditorPHID()]->renderLink(); + + $edit_date = phabricator_datetime($edit->getDateCreated(), $this->user); + + // Something useful could totally go here + $details = ""; + + $rows[] = array( + $editor, + $edit_date, + $details, + ); + } + + $rule_name = phutil_escape_html($this->rule->getName()); + $table = new AphrontTableView($rows); + $table->setNoDataString( + "No edits for \"${rule_name}\""); + $table->setHeaders( + array( + 'Editor', + 'Edit Date', + 'Details', + )); + + $panel = new AphrontPanelView(); + $panel->setHeader("Edit History for \"${rule_name}\""); + $panel->appendChild($table); + + return $panel; + } +} diff --git a/src/applications/herald/view/edithistory/__init__.php b/src/applications/herald/view/edithistory/__init__.php new file mode 100644 index 0000000000..da21a5b70b --- /dev/null +++ b/src/applications/herald/view/edithistory/__init__.php @@ -0,0 +1,17 @@ +user = $user; + return $this; + } + public function render() { $rows = array(); + foreach ($this->rules as $rule) { $owner = $this->handles[$rule->getAuthorPHID()]->renderLink(); @@ -60,6 +66,22 @@ final class HeraldRuleListView extends AphrontView { ), phutil_escape_html($rule->getName())); + $last_edit_date = phabricator_datetime($rule->getDateModified(), + $this->user); + + $view_edits = phutil_render_tag( + 'a', + array( + 'href' => '/herald/history/' . $rule->getID() . '/', + ), + '(View Edits)'); + + $last_edited = phutil_render_tag( + 'span', + array(), + "Last edited on $last_edit_date ${view_edits}"); + + $delete = javelin_render_tag( 'a', array( @@ -73,6 +95,7 @@ final class HeraldRuleListView extends AphrontView { $this->map[$rule->getContentType()], $owner, $name, + $last_edited, $delete, ); } @@ -88,6 +111,7 @@ final class HeraldRuleListView extends AphrontView { 'Type', 'Owner', 'Rule Name', + 'Last Edited', '', )); $table->setColumnClasses( @@ -95,6 +119,7 @@ final class HeraldRuleListView extends AphrontView { '', '', 'wide wrap pri', + '', 'action' )); diff --git a/src/applications/herald/view/rulelist/__init__.php b/src/applications/herald/view/rulelist/__init__.php index a50f4a2beb..9ed50de535 100644 --- a/src/applications/herald/view/rulelist/__init__.php +++ b/src/applications/herald/view/rulelist/__init__.php @@ -10,6 +10,7 @@ phutil_require_module('phabricator', 'infrastructure/javelin/markup'); phutil_require_module('phabricator', 'view/base'); phutil_require_module('phabricator', 'view/control/table'); phutil_require_module('phabricator', 'view/layout/panel'); +phutil_require_module('phabricator', 'view/utils'); phutil_require_module('phutil', 'markup');