@@ -5,6 +5,8 @@ final class NuanceGitHubEventItemType
5
5
6
6
const ITEMTYPE = 'github.event ' ;
7
7
8
+ private $ externalObject ;
9
+
8
10
public function getItemTypeDisplayName () {
9
11
return pht ('GitHub Event ' );
10
12
}
@@ -79,29 +81,13 @@ protected function updateItemFromSource(NuanceItem $item) {
79
81
80
82
// TODO: Link up the requestor, etc.
81
83
82
- $ source = $ item ->getSource ();
83
- $ token = $ source ->getSourceProperty ('github.token ' );
84
- $ token = new PhutilOpaqueEnvelope ($ token );
84
+ $ is_dirty = false ;
85
85
86
- $ ref = $ this ->getDoorkeeperRef ($ item );
87
- if ($ ref ) {
88
- $ ref = id (new DoorkeeperImportEngine ())
89
- ->setViewer ($ viewer )
90
- ->setRefs (array ($ ref ))
91
- ->setThrowOnMissingLink (true )
92
- ->setContextProperty ('github.token ' , $ token )
93
- ->executeOne ();
94
-
95
- if ($ ref ->getSyncFailed ()) {
96
- $ xobj = null ;
97
- } else {
98
- $ xobj = $ ref ->getExternalObject ();
99
- }
86
+ $ xobj = $ this ->reloadExternalObject ($ item );
100
87
101
- if ($ xobj ) {
102
- $ item ->setItemProperty ('doorkeeper.xobj.phid ' , $ xobj ->getPHID ());
103
- $ is_dirty = true ;
104
- }
88
+ if ($ xobj ) {
89
+ $ item ->setItemProperty ('doorkeeper.xobj.phid ' , $ xobj ->getPHID ());
90
+ $ is_dirty = true ;
105
91
}
106
92
107
93
if ($ item ->getStatus () == NuanceItem::STATUS_IMPORTING ) {
@@ -137,6 +123,56 @@ private function getDoorkeeperRef(NuanceItem $item) {
137
123
->setObjectID ($ full_ref );
138
124
}
139
125
126
+ private function reloadExternalObject (NuanceItem $ item , $ local = false ) {
127
+ $ ref = $ this ->getDoorkeeperRef ($ item );
128
+ if (!$ ref ) {
129
+ return null ;
130
+ }
131
+
132
+ $ source = $ item ->getSource ();
133
+ $ token = $ source ->getSourceProperty ('github.token ' );
134
+ $ token = new PhutilOpaqueEnvelope ($ token );
135
+
136
+ $ viewer = $ this ->getViewer ();
137
+
138
+ $ ref = id (new DoorkeeperImportEngine ())
139
+ ->setViewer ($ viewer )
140
+ ->setRefs (array ($ ref ))
141
+ ->setThrowOnMissingLink (true )
142
+ ->setContextProperty ('github.token ' , $ token )
143
+ ->needLocalOnly ($ local )
144
+ ->executeOne ();
145
+
146
+ if ($ ref ->getSyncFailed ()) {
147
+ $ xobj = null ;
148
+ } else {
149
+ $ xobj = $ ref ->getExternalObject ();
150
+ }
151
+
152
+ if ($ xobj ) {
153
+ $ this ->externalObject = $ xobj ;
154
+ }
155
+
156
+ return $ xobj ;
157
+ }
158
+
159
+ private function getExternalObject (NuanceItem $ item ) {
160
+ if ($ this ->externalObject === null ) {
161
+ $ xobj = $ this ->reloadExternalObject ($ item , $ local = true );
162
+ if ($ xobj ) {
163
+ $ this ->externalObject = $ xobj ;
164
+ } else {
165
+ $ this ->externalObject = false ;
166
+ }
167
+ }
168
+
169
+ if ($ this ->externalObject ) {
170
+ return $ this ->externalObject ;
171
+ }
172
+
173
+ return null ;
174
+ }
175
+
140
176
private function newRawEvent (NuanceItem $ item ) {
141
177
$ type = $ item ->getItemProperty ('api.type ' );
142
178
$ raw = $ item ->getItemProperty ('api.raw ' , array ());
@@ -147,6 +183,15 @@ private function newRawEvent(NuanceItem $item) {
147
183
public function getItemActions (NuanceItem $ item ) {
148
184
$ actions = array ();
149
185
186
+ $ xobj = $ this ->getExternalObject ($ item );
187
+ if ($ xobj ) {
188
+ $ actions [] = $ this ->newItemAction ($ item , 'reload ' )
189
+ ->setName (pht ('Reload from GitHub ' ))
190
+ ->setIcon ('fa-refresh ' )
191
+ ->setWorkflow (true )
192
+ ->setRenderAsForm (true );
193
+ }
194
+
150
195
$ actions [] = $ this ->newItemAction ($ item , 'sync ' )
151
196
->setName (pht ('Import to Maniphest ' ))
152
197
->setIcon ('fa-anchor ' )
@@ -189,6 +234,7 @@ protected function handleAction(NuanceItem $item, $action) {
189
234
->appendForm ($ form )
190
235
->addCancelButton ($ item ->getURI (), pht ('Done ' ));
191
236
case 'sync ' :
237
+ case 'reload ' :
192
238
$ item ->issueCommand ($ viewer ->getPHID (), $ action );
193
239
return id (new AphrontRedirectResponse ())->setURI ($ item ->getURI ());
194
240
}
@@ -238,9 +284,117 @@ private function newGitHubEventItemPropertyBox($item) {
238
284
->appendChild ($ property_list );
239
285
}
240
286
241
- protected function handleCommand (NuanceItem $ item , $ action ) {
287
+ protected function handleCommand (
288
+ NuanceItem $ item ,
289
+ NuanceItemCommand $ command ) {
290
+
291
+ $ action = $ command ->getCommand ();
292
+ switch ($ action ) {
293
+ case 'sync ' :
294
+ return $ this ->syncItem ($ item , $ command );
295
+ case 'reload ' :
296
+ $ this ->reloadExternalObject ($ item );
297
+ return true ;
298
+ }
299
+
242
300
return null ;
243
301
}
244
302
303
+ private function syncItem (
304
+ NuanceItem $ item ,
305
+ NuanceItemCommand $ command ) {
306
+
307
+ $ xobj_phid = $ item ->getItemProperty ('doorkeeper.xobj.phid ' );
308
+ if (!$ xobj_phid ) {
309
+ throw new Exception (
310
+ pht (
311
+ 'Unable to sync: no external object PHID. ' ));
312
+ }
313
+
314
+ // TODO: Write some kind of marker to prevent double-synchronization.
315
+
316
+ $ viewer = $ this ->getViewer ();
317
+
318
+ $ xobj = id (new DoorkeeperExternalObjectQuery ())
319
+ ->setViewer ($ viewer )
320
+ ->withPHIDs (array ($ xobj_phid ))
321
+ ->executeOne ();
322
+ if (!$ xobj ) {
323
+ throw new Exception (
324
+ pht (
325
+ 'Unable to sync: failed to load object "%s". ' ,
326
+ $ xobj_phid ));
327
+ }
328
+
329
+ $ nuance_phid = id (new PhabricatorNuanceApplication ())->getPHID ();
330
+
331
+ $ xactions = array ();
332
+
333
+ $ task = id (new ManiphestTaskQuery ())
334
+ ->setViewer ($ viewer )
335
+ ->withBridgedObjectPHIDs (array ($ xobj_phid ))
336
+ ->executeOne ();
337
+ if (!$ task ) {
338
+ $ task = ManiphestTask::initializeNewTask ($ viewer )
339
+ ->setAuthorPHID ($ nuance_phid )
340
+ ->setBridgedObjectPHID ($ xobj_phid );
341
+
342
+ $ title = $ xobj ->getProperty ('task.title ' );
343
+ if (!strlen ($ title )) {
344
+ $ title = pht ('Nuance Item %d Task ' , $ item ->getID ());
345
+ }
346
+
347
+ $ description = $ xobj ->getProperty ('task.description ' );
348
+ $ created = $ xobj ->getProperty ('task.created ' );
349
+ $ state = $ xobj ->getProperty ('task.state ' );
350
+
351
+ $ xactions [] = id (new ManiphestTransaction ())
352
+ ->setTransactionType (ManiphestTransaction::TYPE_TITLE )
353
+ ->setNewValue ($ title )
354
+ ->setDateCreated ($ created );
355
+
356
+ $ xactions [] = id (new ManiphestTransaction ())
357
+ ->setTransactionType (ManiphestTransaction::TYPE_DESCRIPTION )
358
+ ->setNewValue ($ description )
359
+ ->setDateCreated ($ created );
360
+
361
+ $ task ->setDateCreated ($ created );
362
+
363
+ // TODO: Synchronize state.
364
+ }
365
+
366
+ $ event = $ this ->newRawEvent ($ item );
367
+ $ comment = $ event ->getComment ();
368
+ if (strlen ($ comment )) {
369
+ $ xactions [] = id (new ManiphestTransaction ())
370
+ ->setTransactionType (PhabricatorTransactions::TYPE_COMMENT )
371
+ ->attachComment (
372
+ id (new ManiphestTransactionComment ())
373
+ ->setContent ($ comment ));
374
+ }
375
+
376
+ // TODO: Preserve the item's original source.
377
+ $ source = PhabricatorContentSource::newForSource (
378
+ PhabricatorContentSource::SOURCE_DAEMON ,
379
+ array ());
380
+
381
+ // TOOD: This should really be the external source.
382
+ $ acting_phid = $ nuance_phid ;
383
+
384
+ $ editor = id (new ManiphestTransactionEditor ())
385
+ ->setActor ($ viewer )
386
+ ->setActingAsPHID ($ acting_phid )
387
+ ->setContentSource ($ source )
388
+ ->setContinueOnNoEffect (true )
389
+ ->setContinueOnMissingFields (true );
390
+
391
+ $ xactions = $ editor ->applyTransactions ($ task , $ xactions );
392
+
393
+ return array (
394
+ 'objectPHID ' => $ task ->getPHID (),
395
+ 'xactionPHIDs ' => mpull ($ xactions , 'getPHID ' ),
396
+ );
397
+ }
398
+
245
399
246
400
}
0 commit comments