Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/maniphest/storage/ManiphestTask.php
12256 views
1
<?php
2
3
final class ManiphestTask extends ManiphestDAO
4
implements
5
PhabricatorSubscribableInterface,
6
PhabricatorMarkupInterface,
7
PhabricatorPolicyInterface,
8
PhabricatorTokenReceiverInterface,
9
PhabricatorFlaggableInterface,
10
PhabricatorMentionableInterface,
11
PhrequentTrackableInterface,
12
PhabricatorCustomFieldInterface,
13
PhabricatorDestructibleInterface,
14
PhabricatorApplicationTransactionInterface,
15
PhabricatorProjectInterface,
16
PhabricatorSpacesInterface,
17
PhabricatorConduitResultInterface,
18
PhabricatorFulltextInterface,
19
PhabricatorFerretInterface,
20
DoorkeeperBridgedObjectInterface,
21
PhabricatorEditEngineSubtypeInterface,
22
PhabricatorEditEngineLockableInterface,
23
PhabricatorEditEngineMFAInterface,
24
PhabricatorPolicyCodexInterface,
25
PhabricatorUnlockableInterface {
26
27
protected $authorPHID;
28
protected $ownerPHID;
29
30
protected $status;
31
protected $priority;
32
protected $subpriority = 0;
33
34
protected $title = '';
35
protected $description = '';
36
protected $originalEmailSource;
37
protected $mailKey;
38
protected $viewPolicy = PhabricatorPolicies::POLICY_USER;
39
protected $editPolicy = PhabricatorPolicies::POLICY_USER;
40
41
protected $ownerOrdering;
42
protected $spacePHID;
43
protected $bridgedObjectPHID;
44
protected $properties = array();
45
protected $points;
46
protected $subtype;
47
48
protected $closedEpoch;
49
protected $closerPHID;
50
51
private $subscriberPHIDs = self::ATTACHABLE;
52
private $groupByProjectPHID = self::ATTACHABLE;
53
private $customFields = self::ATTACHABLE;
54
private $edgeProjectPHIDs = self::ATTACHABLE;
55
private $bridgedObject = self::ATTACHABLE;
56
57
public static function initializeNewTask(PhabricatorUser $actor) {
58
$app = id(new PhabricatorApplicationQuery())
59
->setViewer($actor)
60
->withClasses(array('PhabricatorManiphestApplication'))
61
->executeOne();
62
63
$view_policy = $app->getPolicy(ManiphestDefaultViewCapability::CAPABILITY);
64
$edit_policy = $app->getPolicy(ManiphestDefaultEditCapability::CAPABILITY);
65
66
return id(new ManiphestTask())
67
->setStatus(ManiphestTaskStatus::getDefaultStatus())
68
->setPriority(ManiphestTaskPriority::getDefaultPriority())
69
->setAuthorPHID($actor->getPHID())
70
->setViewPolicy($view_policy)
71
->setEditPolicy($edit_policy)
72
->setSpacePHID($actor->getDefaultSpacePHID())
73
->setSubtype(PhabricatorEditEngineSubtype::SUBTYPE_DEFAULT)
74
->attachProjectPHIDs(array())
75
->attachSubscriberPHIDs(array());
76
}
77
78
protected function getConfiguration() {
79
return array(
80
self::CONFIG_AUX_PHID => true,
81
self::CONFIG_SERIALIZATION => array(
82
'properties' => self::SERIALIZATION_JSON,
83
),
84
self::CONFIG_COLUMN_SCHEMA => array(
85
'ownerPHID' => 'phid?',
86
'status' => 'text64',
87
'priority' => 'uint32',
88
'title' => 'sort',
89
'description' => 'text',
90
'mailKey' => 'bytes20',
91
'ownerOrdering' => 'text64?',
92
'originalEmailSource' => 'text255?',
93
'subpriority' => 'double',
94
'points' => 'double?',
95
'bridgedObjectPHID' => 'phid?',
96
'subtype' => 'text64',
97
'closedEpoch' => 'epoch?',
98
'closerPHID' => 'phid?',
99
),
100
self::CONFIG_KEY_SCHEMA => array(
101
'key_phid' => null,
102
'phid' => array(
103
'columns' => array('phid'),
104
'unique' => true,
105
),
106
'priority' => array(
107
'columns' => array('priority', 'status'),
108
),
109
'status' => array(
110
'columns' => array('status'),
111
),
112
'ownerPHID' => array(
113
'columns' => array('ownerPHID', 'status'),
114
),
115
'authorPHID' => array(
116
'columns' => array('authorPHID', 'status'),
117
),
118
'ownerOrdering' => array(
119
'columns' => array('ownerOrdering'),
120
),
121
'priority_2' => array(
122
'columns' => array('priority', 'subpriority'),
123
),
124
'key_dateCreated' => array(
125
'columns' => array('dateCreated'),
126
),
127
'key_dateModified' => array(
128
'columns' => array('dateModified'),
129
),
130
'key_title' => array(
131
'columns' => array('title(64)'),
132
),
133
'key_bridgedobject' => array(
134
'columns' => array('bridgedObjectPHID'),
135
'unique' => true,
136
),
137
'key_subtype' => array(
138
'columns' => array('subtype'),
139
),
140
'key_closed' => array(
141
'columns' => array('closedEpoch'),
142
),
143
'key_closer' => array(
144
'columns' => array('closerPHID', 'closedEpoch'),
145
),
146
),
147
) + parent::getConfiguration();
148
}
149
150
public function loadDependsOnTaskPHIDs() {
151
return PhabricatorEdgeQuery::loadDestinationPHIDs(
152
$this->getPHID(),
153
ManiphestTaskDependsOnTaskEdgeType::EDGECONST);
154
}
155
156
public function loadDependedOnByTaskPHIDs() {
157
return PhabricatorEdgeQuery::loadDestinationPHIDs(
158
$this->getPHID(),
159
ManiphestTaskDependedOnByTaskEdgeType::EDGECONST);
160
}
161
162
public function generatePHID() {
163
return PhabricatorPHID::generateNewPHID(ManiphestTaskPHIDType::TYPECONST);
164
}
165
166
public function getSubscriberPHIDs() {
167
return $this->assertAttached($this->subscriberPHIDs);
168
}
169
170
public function getProjectPHIDs() {
171
return $this->assertAttached($this->edgeProjectPHIDs);
172
}
173
174
public function attachProjectPHIDs(array $phids) {
175
$this->edgeProjectPHIDs = $phids;
176
return $this;
177
}
178
179
public function attachSubscriberPHIDs(array $phids) {
180
$this->subscriberPHIDs = $phids;
181
return $this;
182
}
183
184
public function setOwnerPHID($phid) {
185
$this->ownerPHID = nonempty($phid, null);
186
return $this;
187
}
188
189
public function getMonogram() {
190
return 'T'.$this->getID();
191
}
192
193
public function getURI() {
194
return '/'.$this->getMonogram();
195
}
196
197
public function attachGroupByProjectPHID($phid) {
198
$this->groupByProjectPHID = $phid;
199
return $this;
200
}
201
202
public function getGroupByProjectPHID() {
203
return $this->assertAttached($this->groupByProjectPHID);
204
}
205
206
public function save() {
207
if (!$this->mailKey) {
208
$this->mailKey = Filesystem::readRandomCharacters(20);
209
}
210
211
$result = parent::save();
212
213
return $result;
214
}
215
216
public function isClosed() {
217
return ManiphestTaskStatus::isClosedStatus($this->getStatus());
218
}
219
220
public function areCommentsLocked() {
221
if ($this->areEditsLocked()) {
222
return true;
223
}
224
225
return ManiphestTaskStatus::areCommentsLockedInStatus($this->getStatus());
226
}
227
228
public function areEditsLocked() {
229
return ManiphestTaskStatus::areEditsLockedInStatus($this->getStatus());
230
}
231
232
public function setProperty($key, $value) {
233
$this->properties[$key] = $value;
234
return $this;
235
}
236
237
public function getProperty($key, $default = null) {
238
return idx($this->properties, $key, $default);
239
}
240
241
public function getCoverImageFilePHID() {
242
return idx($this->properties, 'cover.filePHID');
243
}
244
245
public function getCoverImageThumbnailPHID() {
246
return idx($this->properties, 'cover.thumbnailPHID');
247
}
248
249
public function getPriorityKeyword() {
250
$priority = $this->getPriority();
251
252
$keyword = ManiphestTaskPriority::getKeywordForTaskPriority($priority);
253
if ($keyword !== null) {
254
return $keyword;
255
}
256
257
return ManiphestTaskPriority::UNKNOWN_PRIORITY_KEYWORD;
258
}
259
260
261
/* -( PhabricatorSubscribableInterface )----------------------------------- */
262
263
264
public function isAutomaticallySubscribed($phid) {
265
return ($phid == $this->getOwnerPHID());
266
}
267
268
269
/* -( Markup Interface )--------------------------------------------------- */
270
271
272
/**
273
* @task markup
274
*/
275
public function getMarkupFieldKey($field) {
276
$content = $this->getMarkupText($field);
277
return PhabricatorMarkupEngine::digestRemarkupContent($this, $content);
278
}
279
280
281
/**
282
* @task markup
283
*/
284
public function getMarkupText($field) {
285
return $this->getDescription();
286
}
287
288
289
/**
290
* @task markup
291
*/
292
public function newMarkupEngine($field) {
293
return PhabricatorMarkupEngine::newManiphestMarkupEngine();
294
}
295
296
297
/**
298
* @task markup
299
*/
300
public function didMarkupText(
301
$field,
302
$output,
303
PhutilMarkupEngine $engine) {
304
return $output;
305
}
306
307
308
/**
309
* @task markup
310
*/
311
public function shouldUseMarkupCache($field) {
312
return (bool)$this->getID();
313
}
314
315
316
/* -( Policy Interface )--------------------------------------------------- */
317
318
319
public function getCapabilities() {
320
return array(
321
PhabricatorPolicyCapability::CAN_VIEW,
322
PhabricatorPolicyCapability::CAN_INTERACT,
323
PhabricatorPolicyCapability::CAN_EDIT,
324
);
325
}
326
327
public function getPolicy($capability) {
328
switch ($capability) {
329
case PhabricatorPolicyCapability::CAN_VIEW:
330
return $this->getViewPolicy();
331
case PhabricatorPolicyCapability::CAN_INTERACT:
332
if ($this->areCommentsLocked()) {
333
return PhabricatorPolicies::POLICY_NOONE;
334
} else {
335
return $this->getViewPolicy();
336
}
337
case PhabricatorPolicyCapability::CAN_EDIT:
338
if ($this->areEditsLocked()) {
339
return PhabricatorPolicies::POLICY_NOONE;
340
} else {
341
return $this->getEditPolicy();
342
}
343
}
344
}
345
346
public function hasAutomaticCapability($capability, PhabricatorUser $user) {
347
// The owner of a task can always view and edit it.
348
$owner_phid = $this->getOwnerPHID();
349
if ($owner_phid) {
350
$user_phid = $user->getPHID();
351
if ($user_phid == $owner_phid) {
352
return true;
353
}
354
}
355
356
return false;
357
}
358
359
360
/* -( PhabricatorTokenReceiverInterface )---------------------------------- */
361
362
363
public function getUsersToNotifyOfTokenGiven() {
364
// Sort of ambiguous who this was intended for; just let them both know.
365
return array_filter(
366
array_unique(
367
array(
368
$this->getAuthorPHID(),
369
$this->getOwnerPHID(),
370
)));
371
}
372
373
374
/* -( PhabricatorCustomFieldInterface )------------------------------------ */
375
376
377
public function getCustomFieldSpecificationForRole($role) {
378
return PhabricatorEnv::getEnvConfig('maniphest.fields');
379
}
380
381
public function getCustomFieldBaseClass() {
382
return 'ManiphestCustomField';
383
}
384
385
public function getCustomFields() {
386
return $this->assertAttached($this->customFields);
387
}
388
389
public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) {
390
$this->customFields = $fields;
391
return $this;
392
}
393
394
395
/* -( PhabricatorDestructibleInterface )----------------------------------- */
396
397
398
public function destroyObjectPermanently(
399
PhabricatorDestructionEngine $engine) {
400
401
$this->openTransaction();
402
$this->delete();
403
$this->saveTransaction();
404
}
405
406
407
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
408
409
410
public function getApplicationTransactionEditor() {
411
return new ManiphestTransactionEditor();
412
}
413
414
public function getApplicationTransactionTemplate() {
415
return new ManiphestTransaction();
416
}
417
418
419
/* -( PhabricatorSpacesInterface )----------------------------------------- */
420
421
422
public function getSpacePHID() {
423
return $this->spacePHID;
424
}
425
426
427
/* -( PhabricatorConduitResultInterface )---------------------------------- */
428
429
430
public function getFieldSpecificationsForConduit() {
431
return array(
432
id(new PhabricatorConduitSearchFieldSpecification())
433
->setKey('title')
434
->setType('string')
435
->setDescription(pht('The title of the task.')),
436
id(new PhabricatorConduitSearchFieldSpecification())
437
->setKey('description')
438
->setType('remarkup')
439
->setDescription(pht('The task description.')),
440
id(new PhabricatorConduitSearchFieldSpecification())
441
->setKey('authorPHID')
442
->setType('phid')
443
->setDescription(pht('Original task author.')),
444
id(new PhabricatorConduitSearchFieldSpecification())
445
->setKey('ownerPHID')
446
->setType('phid?')
447
->setDescription(pht('Current task owner, if task is assigned.')),
448
id(new PhabricatorConduitSearchFieldSpecification())
449
->setKey('status')
450
->setType('map<string, wild>')
451
->setDescription(pht('Information about task status.')),
452
id(new PhabricatorConduitSearchFieldSpecification())
453
->setKey('priority')
454
->setType('map<string, wild>')
455
->setDescription(pht('Information about task priority.')),
456
id(new PhabricatorConduitSearchFieldSpecification())
457
->setKey('points')
458
->setType('points')
459
->setDescription(pht('Point value of the task.')),
460
id(new PhabricatorConduitSearchFieldSpecification())
461
->setKey('subtype')
462
->setType('string')
463
->setDescription(pht('Subtype of the task.')),
464
id(new PhabricatorConduitSearchFieldSpecification())
465
->setKey('closerPHID')
466
->setType('phid?')
467
->setDescription(
468
pht('User who closed the task, if the task is closed.')),
469
id(new PhabricatorConduitSearchFieldSpecification())
470
->setKey('dateClosed')
471
->setType('int?')
472
->setDescription(
473
pht('Epoch timestamp when the task was closed.')),
474
);
475
}
476
477
public function getFieldValuesForConduit() {
478
$status_value = $this->getStatus();
479
$status_info = array(
480
'value' => $status_value,
481
'name' => ManiphestTaskStatus::getTaskStatusName($status_value),
482
'color' => ManiphestTaskStatus::getStatusColor($status_value),
483
);
484
485
$priority_value = (int)$this->getPriority();
486
$priority_info = array(
487
'value' => $priority_value,
488
'name' => ManiphestTaskPriority::getTaskPriorityName($priority_value),
489
'color' => ManiphestTaskPriority::getTaskPriorityColor($priority_value),
490
);
491
492
$closed_epoch = $this->getClosedEpoch();
493
if ($closed_epoch !== null) {
494
$closed_epoch = (int)$closed_epoch;
495
}
496
497
return array(
498
'name' => $this->getTitle(),
499
'description' => array(
500
'raw' => $this->getDescription(),
501
),
502
'authorPHID' => $this->getAuthorPHID(),
503
'ownerPHID' => $this->getOwnerPHID(),
504
'status' => $status_info,
505
'priority' => $priority_info,
506
'points' => $this->getPoints(),
507
'subtype' => $this->getSubtype(),
508
'closerPHID' => $this->getCloserPHID(),
509
'dateClosed' => $closed_epoch,
510
);
511
}
512
513
public function getConduitSearchAttachments() {
514
return array(
515
id(new PhabricatorBoardColumnsSearchEngineAttachment())
516
->setAttachmentKey('columns'),
517
);
518
}
519
520
public function newSubtypeObject() {
521
$subtype_key = $this->getEditEngineSubtype();
522
$subtype_map = $this->newEditEngineSubtypeMap();
523
return $subtype_map->getSubtype($subtype_key);
524
}
525
526
/* -( PhabricatorFulltextInterface )--------------------------------------- */
527
528
529
public function newFulltextEngine() {
530
return new ManiphestTaskFulltextEngine();
531
}
532
533
534
/* -( DoorkeeperBridgedObjectInterface )----------------------------------- */
535
536
537
public function getBridgedObject() {
538
return $this->assertAttached($this->bridgedObject);
539
}
540
541
public function attachBridgedObject(
542
DoorkeeperExternalObject $object = null) {
543
$this->bridgedObject = $object;
544
return $this;
545
}
546
547
548
/* -( PhabricatorEditEngineSubtypeInterface )------------------------------ */
549
550
551
public function getEditEngineSubtype() {
552
return $this->getSubtype();
553
}
554
555
public function setEditEngineSubtype($value) {
556
return $this->setSubtype($value);
557
}
558
559
public function newEditEngineSubtypeMap() {
560
$config = PhabricatorEnv::getEnvConfig('maniphest.subtypes');
561
return PhabricatorEditEngineSubtype::newSubtypeMap($config)
562
->setDatasource(new ManiphestTaskSubtypeDatasource());
563
}
564
565
566
/* -( PhabricatorEditEngineLockableInterface )----------------------------- */
567
568
569
public function newEditEngineLock() {
570
return new ManiphestTaskEditEngineLock();
571
}
572
573
574
/* -( PhabricatorFerretInterface )----------------------------------------- */
575
576
577
public function newFerretEngine() {
578
return new ManiphestTaskFerretEngine();
579
}
580
581
582
/* -( PhabricatorEditEngineMFAInterface )---------------------------------- */
583
584
585
public function newEditEngineMFAEngine() {
586
return new ManiphestTaskMFAEngine();
587
}
588
589
590
/* -( PhabricatorPolicyCodexInterface )------------------------------------ */
591
592
593
public function newPolicyCodex() {
594
return new ManiphestTaskPolicyCodex();
595
}
596
597
598
/* -( PhabricatorUnlockableInterface )------------------------------------- */
599
600
601
public function newUnlockEngine() {
602
return new ManiphestTaskUnlockEngine();
603
}
604
605
}
606
607