Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/differential/xaction/DifferentialRevisionActionTransaction.php
12256 views
1
<?php
2
3
abstract class DifferentialRevisionActionTransaction
4
extends DifferentialRevisionTransactionType {
5
6
final public function getRevisionActionKey() {
7
return $this->getPhobjectClassConstant('ACTIONKEY', 32);
8
}
9
10
public function isActionAvailable($object, PhabricatorUser $viewer) {
11
try {
12
$this->validateAction($object, $viewer);
13
return true;
14
} catch (Exception $ex) {
15
return false;
16
}
17
}
18
19
abstract protected function validateAction($object, PhabricatorUser $viewer);
20
abstract protected function getRevisionActionLabel(
21
DifferentialRevision $revision,
22
PhabricatorUser $viewer);
23
24
protected function validateOptionValue($object, $actor, array $value) {
25
return null;
26
}
27
28
public function getCommandKeyword() {
29
return null;
30
}
31
32
public function getCommandAliases() {
33
return array();
34
}
35
36
public function getCommandSummary() {
37
return null;
38
}
39
40
protected function getRevisionActionOrder() {
41
return 1000;
42
}
43
44
public function getActionStrength() {
45
return 300;
46
}
47
48
public function getRevisionActionOrderVector() {
49
return id(new PhutilSortVector())
50
->addInt($this->getRevisionActionOrder());
51
}
52
53
protected function getRevisionActionGroupKey() {
54
return DifferentialRevisionEditEngine::ACTIONGROUP_REVISION;
55
}
56
57
protected function getRevisionActionDescription(
58
DifferentialRevision $revision,
59
PhabricatorUser $viewer) {
60
return null;
61
}
62
63
protected function getRevisionActionSubmitButtonText(
64
DifferentialRevision $revision,
65
PhabricatorUser $viewer) {
66
return null;
67
}
68
69
protected function getRevisionActionMetadata(
70
DifferentialRevision $revision,
71
PhabricatorUser $viewer) {
72
return array();
73
}
74
75
public static function loadAllActions() {
76
return id(new PhutilClassMapQuery())
77
->setAncestorClass(__CLASS__)
78
->setUniqueMethod('getRevisionActionKey')
79
->execute();
80
}
81
82
protected function isViewerRevisionAuthor(
83
DifferentialRevision $revision,
84
PhabricatorUser $viewer) {
85
86
if (!$viewer->getPHID()) {
87
return false;
88
}
89
90
return ($viewer->getPHID() === $revision->getAuthorPHID());
91
}
92
93
protected function getActionOptions(
94
PhabricatorUser $viewer,
95
DifferentialRevision $revision) {
96
return array(
97
array(),
98
array(),
99
);
100
}
101
102
public function newEditField(
103
DifferentialRevision $revision,
104
PhabricatorUser $viewer) {
105
106
// Actions in the "review" group, like "Accept Revision", do not require
107
// that the actor be able to edit the revision.
108
$group_review = DifferentialRevisionEditEngine::ACTIONGROUP_REVIEW;
109
$is_review = ($this->getRevisionActionGroupKey() == $group_review);
110
111
$field = id(new PhabricatorApplyEditField())
112
->setKey($this->getRevisionActionKey())
113
->setTransactionType($this->getTransactionTypeConstant())
114
->setCanApplyWithoutEditCapability($is_review)
115
->setValue(true);
116
117
if ($this->isActionAvailable($revision, $viewer)) {
118
$label = $this->getRevisionActionLabel($revision, $viewer);
119
if ($label !== null) {
120
$field->setCommentActionLabel($label);
121
122
$description = $this->getRevisionActionDescription($revision, $viewer);
123
$field->setActionDescription($description);
124
125
$group_key = $this->getRevisionActionGroupKey();
126
$field->setCommentActionGroupKey($group_key);
127
128
$button_text = $this->getRevisionActionSubmitButtonText(
129
$revision,
130
$viewer);
131
$field->setActionSubmitButtonText($button_text);
132
133
// Currently, every revision action conflicts with every other
134
// revision action: for example, you can not simultaneously Accept and
135
// Reject a revision.
136
137
// Under some configurations, some combinations of actions are sort of
138
// technically permissible. For example, you could reasonably Reject
139
// and Abandon a revision if "anyone can abandon anything" is enabled.
140
141
// It's not clear that these combinations are actually useful, so just
142
// keep things simple for now.
143
$field->setActionConflictKey('revision.action');
144
145
list($options, $value) = $this->getActionOptions($viewer, $revision);
146
147
// Show the options if the user can select on behalf of two or more
148
// reviewers, or can force-accept on behalf of one or more reviewers,
149
// or can accept on behalf of a reviewer other than themselves (see
150
// T12533).
151
$can_multi = (count($options) > 1);
152
$can_force = (count($value) < count($options));
153
$not_self = (head_key($options) != $viewer->getPHID());
154
155
if ($can_multi || $can_force || $not_self) {
156
$field->setOptions($options);
157
$field->setValue($value);
158
}
159
160
$metadata = $this->getRevisionActionMetadata($revision, $viewer);
161
foreach ($metadata as $metadata_key => $metadata_value) {
162
$field->setMetadataValue($metadata_key, $metadata_value);
163
}
164
}
165
}
166
167
return $field;
168
}
169
170
public function validateTransactions($object, array $xactions) {
171
$errors = array();
172
$actor = $this->getActor();
173
174
$action_exception = null;
175
foreach ($xactions as $xaction) {
176
// If this is a draft demotion action, let it skip all the normal
177
// validation. This is a little hacky and should perhaps move down
178
// into the actual action implementations, but currently we can not
179
// apply this rule in validateAction() because it doesn't operate on
180
// the actual transaction.
181
if ($xaction->getMetadataValue('draft.demote')) {
182
continue;
183
}
184
185
try {
186
$this->validateAction($object, $actor);
187
} catch (Exception $ex) {
188
$action_exception = $ex;
189
}
190
191
break;
192
}
193
194
foreach ($xactions as $xaction) {
195
if ($action_exception) {
196
$errors[] = $this->newInvalidError(
197
$action_exception->getMessage(),
198
$xaction);
199
continue;
200
}
201
202
$new = $xaction->getNewValue();
203
if (!is_array($new)) {
204
continue;
205
}
206
207
try {
208
$this->validateOptionValue($object, $actor, $new);
209
} catch (Exception $ex) {
210
$errors[] = $this->newInvalidError(
211
$ex->getMessage(),
212
$xaction);
213
}
214
}
215
216
return $errors;
217
}
218
219
}
220
221