Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/maniphest/conduit/ManiphestConduitAPIMethod.php
12256 views
1
<?php
2
3
abstract class ManiphestConduitAPIMethod extends ConduitAPIMethod {
4
5
final public function getApplication() {
6
return PhabricatorApplication::getByClass(
7
'PhabricatorManiphestApplication');
8
}
9
10
protected function defineErrorTypes() {
11
return array(
12
'ERR-INVALID-PARAMETER' => pht('Missing or malformed parameter.'),
13
);
14
}
15
16
protected function buildTaskInfoDictionary(ManiphestTask $task) {
17
$results = $this->buildTaskInfoDictionaries(array($task));
18
return idx($results, $task->getPHID());
19
}
20
21
protected function getTaskFields($is_new) {
22
$fields = array();
23
24
if (!$is_new) {
25
$fields += array(
26
'id' => 'optional int',
27
'phid' => 'optional int',
28
);
29
}
30
31
$fields += array(
32
'title' => $is_new ? 'required string' : 'optional string',
33
'description' => 'optional string',
34
'ownerPHID' => 'optional phid',
35
'viewPolicy' => 'optional phid or policy string',
36
'editPolicy' => 'optional phid or policy string',
37
'ccPHIDs' => 'optional list<phid>',
38
'priority' => 'optional int',
39
'projectPHIDs' => 'optional list<phid>',
40
'auxiliary' => 'optional dict',
41
);
42
43
if (!$is_new) {
44
$fields += array(
45
'status' => 'optional string',
46
'comments' => 'optional string',
47
);
48
}
49
50
return $fields;
51
}
52
53
protected function applyRequest(
54
ManiphestTask $task,
55
ConduitAPIRequest $request,
56
$is_new) {
57
58
$changes = array();
59
60
if ($is_new) {
61
$task->setTitle((string)$request->getValue('title'));
62
$task->setDescription((string)$request->getValue('description'));
63
$changes[ManiphestTaskStatusTransaction::TRANSACTIONTYPE] =
64
ManiphestTaskStatus::getDefaultStatus();
65
$changes[PhabricatorTransactions::TYPE_SUBSCRIBERS] =
66
array('+' => array($request->getUser()->getPHID()));
67
} else {
68
69
$comments = $request->getValue('comments');
70
if (!$is_new && $comments !== null) {
71
$changes[PhabricatorTransactions::TYPE_COMMENT] = null;
72
}
73
74
$title = $request->getValue('title');
75
if ($title !== null) {
76
$changes[ManiphestTaskTitleTransaction::TRANSACTIONTYPE] = $title;
77
}
78
79
$desc = $request->getValue('description');
80
if ($desc !== null) {
81
$changes[ManiphestTaskDescriptionTransaction::TRANSACTIONTYPE] = $desc;
82
}
83
84
$status = $request->getValue('status');
85
if ($status !== null) {
86
$valid_statuses = ManiphestTaskStatus::getTaskStatusMap();
87
if (!isset($valid_statuses[$status])) {
88
throw id(new ConduitException('ERR-INVALID-PARAMETER'))
89
->setErrorDescription(pht('Status set to invalid value.'));
90
}
91
$changes[ManiphestTaskStatusTransaction::TRANSACTIONTYPE] = $status;
92
}
93
}
94
95
$priority = $request->getValue('priority');
96
if ($priority !== null) {
97
$valid_priorities = ManiphestTaskPriority::getTaskPriorityMap();
98
if (!isset($valid_priorities[$priority])) {
99
throw id(new ConduitException('ERR-INVALID-PARAMETER'))
100
->setErrorDescription(pht('Priority set to invalid value.'));
101
}
102
$keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap();
103
$keyword = head(idx($keyword_map, $priority));
104
$changes[ManiphestTaskPriorityTransaction::TRANSACTIONTYPE] = $keyword;
105
}
106
107
$owner_phid = $request->getValue('ownerPHID');
108
if ($owner_phid !== null) {
109
$this->validatePHIDList(
110
array($owner_phid),
111
PhabricatorPeopleUserPHIDType::TYPECONST,
112
'ownerPHID');
113
$changes[ManiphestTaskOwnerTransaction::TRANSACTIONTYPE] = $owner_phid;
114
}
115
116
$ccs = $request->getValue('ccPHIDs');
117
if ($ccs !== null) {
118
$changes[PhabricatorTransactions::TYPE_SUBSCRIBERS] =
119
array('=' => array_fuse($ccs));
120
}
121
122
$transactions = array();
123
124
$view_policy = $request->getValue('viewPolicy');
125
if ($view_policy !== null) {
126
$transactions[] = id(new ManiphestTransaction())
127
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
128
->setNewValue($view_policy);
129
}
130
131
$edit_policy = $request->getValue('editPolicy');
132
if ($edit_policy !== null) {
133
$transactions[] = id(new ManiphestTransaction())
134
->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
135
->setNewValue($edit_policy);
136
}
137
138
$project_phids = $request->getValue('projectPHIDs');
139
if ($project_phids !== null) {
140
$this->validatePHIDList(
141
$project_phids,
142
PhabricatorProjectProjectPHIDType::TYPECONST,
143
'projectPHIDS');
144
145
$project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
146
$transactions[] = id(new ManiphestTransaction())
147
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
148
->setMetadataValue('edge:type', $project_type)
149
->setNewValue(
150
array(
151
'=' => array_fuse($project_phids),
152
));
153
}
154
155
$template = new ManiphestTransaction();
156
157
foreach ($changes as $type => $value) {
158
$transaction = clone $template;
159
$transaction->setTransactionType($type);
160
if ($type == PhabricatorTransactions::TYPE_COMMENT) {
161
$transaction->attachComment(
162
id(new ManiphestTransactionComment())
163
->setContent($comments));
164
} else {
165
$transaction->setNewValue($value);
166
}
167
168
$transactions[] = $transaction;
169
}
170
171
$field_list = PhabricatorCustomField::getObjectFields(
172
$task,
173
PhabricatorCustomField::ROLE_EDIT);
174
$field_list->readFieldsFromStorage($task);
175
176
$auxiliary = $request->getValue('auxiliary');
177
if ($auxiliary) {
178
foreach ($field_list->getFields() as $key => $field) {
179
if (!array_key_exists($key, $auxiliary)) {
180
continue;
181
}
182
$transaction = clone $template;
183
$transaction->setTransactionType(
184
PhabricatorTransactions::TYPE_CUSTOMFIELD);
185
$transaction->setMetadataValue('customfield:key', $key);
186
$transaction->setOldValue(
187
$field->getOldValueForApplicationTransactions());
188
$transaction->setNewValue($auxiliary[$key]);
189
$transactions[] = $transaction;
190
}
191
}
192
193
if (!$transactions) {
194
return;
195
}
196
197
$content_source = $request->newContentSource();
198
199
$editor = id(new ManiphestTransactionEditor())
200
->setActor($request->getUser())
201
->setContentSource($content_source)
202
->setContinueOnNoEffect(true);
203
204
if (!$is_new) {
205
$editor->setContinueOnMissingFields(true);
206
}
207
208
$editor->applyTransactions($task, $transactions);
209
210
// reload the task now that we've done all the fun stuff
211
return id(new ManiphestTaskQuery())
212
->setViewer($request->getUser())
213
->withPHIDs(array($task->getPHID()))
214
->needSubscriberPHIDs(true)
215
->needProjectPHIDs(true)
216
->executeOne();
217
}
218
219
protected function buildTaskInfoDictionaries(array $tasks) {
220
assert_instances_of($tasks, 'ManiphestTask');
221
if (!$tasks) {
222
return array();
223
}
224
225
$task_phids = mpull($tasks, 'getPHID');
226
227
$all_deps = id(new PhabricatorEdgeQuery())
228
->withSourcePHIDs($task_phids)
229
->withEdgeTypes(array(ManiphestTaskDependsOnTaskEdgeType::EDGECONST));
230
$all_deps->execute();
231
232
$result = array();
233
foreach ($tasks as $task) {
234
// TODO: Batch this get as CustomField gets cleaned up.
235
$field_list = PhabricatorCustomField::getObjectFields(
236
$task,
237
PhabricatorCustomField::ROLE_EDIT);
238
$field_list->readFieldsFromStorage($task);
239
240
$auxiliary = mpull(
241
$field_list->getFields(),
242
'getValueForStorage',
243
'getFieldKey');
244
245
$task_deps = $all_deps->getDestinationPHIDs(
246
array($task->getPHID()),
247
array(ManiphestTaskDependsOnTaskEdgeType::EDGECONST));
248
249
$result[$task->getPHID()] = array(
250
'id' => $task->getID(),
251
'phid' => $task->getPHID(),
252
'authorPHID' => $task->getAuthorPHID(),
253
'ownerPHID' => $task->getOwnerPHID(),
254
'ccPHIDs' => $task->getSubscriberPHIDs(),
255
'status' => $task->getStatus(),
256
'statusName' => ManiphestTaskStatus::getTaskStatusName(
257
$task->getStatus()),
258
'isClosed' => $task->isClosed(),
259
'priority' => ManiphestTaskPriority::getTaskPriorityName(
260
$task->getPriority()),
261
'priorityColor' => ManiphestTaskPriority::getTaskPriorityColor(
262
$task->getPriority()),
263
'title' => $task->getTitle(),
264
'description' => $task->getDescription(),
265
'projectPHIDs' => $task->getProjectPHIDs(),
266
'uri' => PhabricatorEnv::getProductionURI('/T'.$task->getID()),
267
'auxiliary' => $auxiliary,
268
269
'objectName' => 'T'.$task->getID(),
270
'dateCreated' => $task->getDateCreated(),
271
'dateModified' => $task->getDateModified(),
272
'dependsOnTaskPHIDs' => $task_deps,
273
);
274
}
275
276
return $result;
277
}
278
279
/**
280
* NOTE: This is a temporary stop gap since its easy to make malformed tasks.
281
* Long-term, the values set in @{method:defineParamTypes} will be used to
282
* validate data implicitly within the larger Conduit application.
283
*
284
* TODO: Remove this in favor of generalized Conduit hotness.
285
*/
286
private function validatePHIDList(array $phid_list, $phid_type, $field) {
287
$phid_groups = phid_group_by_type($phid_list);
288
unset($phid_groups[$phid_type]);
289
if (!empty($phid_groups)) {
290
throw id(new ConduitException('ERR-INVALID-PARAMETER'))
291
->setErrorDescription(
292
pht(
293
'One or more PHIDs were invalid for %s.',
294
$field));
295
}
296
297
return true;
298
}
299
300
}
301
302