Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
startsynccontroller.php
1<?php
2
4
5use Bitrix\Calendar\Core;
9use Bitrix\Calendar\Sync\Util\HandleStatusTrait;
21use Bitrix\Dav\Internals\DavConnectionTable;
28use CCalendar;
29use COption;
30use Exception;
31use Psr\Container\NotFoundExceptionInterface;
32use Throwable;
33
35{
37
38 private const STATUSES = [
39 'connection_created' => 'connection_created',
40 'connection_renamed' => 'connection_renamed',
41 'sections_sync_finished' => 'sections_sync_finished',
42 'events_sync_finished' => 'events_sync_finished',
43 'subscribe_finished' => 'subscribe_finished',
44 'all_finished' => 'all_finished',
45 'export_finished' => 'export_finished',
46 ];
47
51 private string $accountName = '';
55 private Role $owner;
56
60 public function __construct(Role $owner)
61 {
62 $this->owner = $owner;
63 }
64
71 public function synchronize(): array
72 {
73 $response = [
74 'status' => 'success',
75 'message' => 'CONNECTION_CREATED'
76 ];
77
78 $owner = \Bitrix\Calendar\Core\Role\Helper::getRole(\CCalendar::GetUserId(), User::TYPE);
79 $pusher = static function ($result) use ($owner)
80 {
82 'process_sync_connection',
83 $owner->getId(),
84 (array) $result
85 );
86
87 if ($result['stage'] === self::STATUSES['export_finished'])
88 {
89 NotificationManager::addFinishedSyncNotificationAgent(
90 $owner->getId(),
91 $result['vendorName']
92 );
93 }
94 };
95
96 try
97 {
98 // start process
99 if ($connection = $this->addStatusHandler($pusher)->start())
100 {
101 $response['connectionId'] = $connection->getId();
102 }
103 else
104 {
105 $response['connectionId'] = null;
106 }
107 }
108 catch (\Throwable $e)
109 {
110 $response = [
111 'status' => 'error',
112 'message' => 'Could not finish sync: '.$e->getMessage()
113 ];
114 }
115
116 return $response;
117 }
118
128 public function start(): ?Connection
129 {
131 if ($connection = $this->initConnection())
132 {
133 // TODO: change it to disabling update sections agent
134 $this->muteConnection($connection, true);
135 $status = self::STATUSES['connection_created'];
136 try
137 {
138 $connection = $this->fixUglyAccountName($connection);
139 $this->sendResult($status);
140 // $status = self::STATUSES['connection_renamed']; // this status is virtual. We can't roll back it.
141
142 $factory = new Factory($connection);
143
144 $exchangeManager = new VendorDataExchangeManager(
145 $factory,
146 (new SyncSectionFactory())->getSyncSectionMapByFactory($factory)
147 );
148
149 $exchangeManager
150 ->addStatusHandlerList($this->getStatusHandlerList())
151 ->exchange();
152
153 $status = self::STATUSES['export_finished'];
154 $this->sendResult($status);
155
156 if ($this->isPushEnabled())
157 {
158 $this->initSubscription($connection);
159// $status = self::STATUSES['subscribe_finished'];
160// $this->sendResult($status);
161 }
162
163 $this->setConnectionStatus($connection, Sync\Dictionary::SYNC_STATUS['success']);
164
165 $this->muteConnection($connection, false);
166 return $connection;
167 }
168 catch (SyncException|Throwable $e)
169 {
170 // TODO: remove Throwable after finish of testing
171 $this->rollBack($connection);
172 throw $e;
173 }
174 }
175
176 throw new SyncException('Error of create connection');
177 }
178
185 private function muteConnection(Connection $connection, bool $state)
186 {
187 $original = $connection->isDeleted();
188 $connection->setDeleted($state);
189 (new Core\Mappers\Connection())->update($connection);
190 $connection->setDeleted($original);
191 }
192
196 private function initConnection(): ?Connection
197 {
198 $connectionManager = new ConnectionManager();
199 $result = $connectionManager->initConnection(
200 $this->owner,
203 );
204 if ($result->isSuccess())
205 {
206 return $result->getData()['connection'];
207 }
208
209 return null;
210 }
211
217 private function sendResult(string $stage)
218 {
219 $this->sendStatus([
220 'vendorName' => Helper::ACCOUNT_TYPE,
221 'accountName' => $this->getAccountName(),
222 'stage' => $stage,
223 ]);
224 }
225
229 private function getAccountName(): string
230 {
231 return $this->accountName ?? '';
232 }
233
234 private array $outgoingManagersCache = [];
242 private function getOutgoingManager(Connection $connection)
243 {
244
245 if (empty($this->outgoingManagersCache[$connection->getId()]))
246 {
247 $this->outgoingManagersCache[$connection->getId()] = new OutgoingManager($connection);
248 }
249
250 return $this->outgoingManagersCache[$connection->getId()];
251 }
252
258 private function initSubscription(Connection $connection): Result
259 {
260 $result = new Result();
261 try
262 {
263 $links = (new Core\Mappers\SectionConnection())->getMap([
264 '=CONNECTION_ID' => $connection->getId(),
265 '=ACTIVE' => 'Y'
266 ]);
267 $manager = $this->getOutgoingManager($connection);
268 foreach ($links as $link)
269 {
270 try
271 {
272 $manager->subscribeSection($link);
273 }
274 catch (Exception $e)
275 {
276 $result->addError(new Error($e->getMessage(), $e->getCode()));
277 }
278 }
279 }
280 catch (Exception $e)
281 {
282 $result->addError(new Error($e->getMessage(), $e->getCode()));
283 }
284
285 return $result;
286 }
287
296 private function setConnectionStatus(Connection $connection, string $status)
297 {
298 DavConnectionTable::update($connection->getId(), [
299 'LAST_RESULT' => $status,
300 ]);
301 }
302
310 private function fixUglyAccountName(Connection $connection): Connection
311 {
312 if (substr($connection->getName(), 0,9) === 'Office365')
313 {
314 $currentName = $connection->getName();
315 try {
316 $context = Office365Context::getConnectionContext($connection);
317 $userData = $context->getApiClient()->get('me');
318 if (!empty($userData['userPrincipalName']))
319 {
320 if ($oldConnection = $this->getConnection(
321 $connection->getOwner(),
323 $userData['userPrincipalName']
324 ))
325 {
326 $oldConnection->setDeleted(false);
327 (new Core\Mappers\Connection())->delete($connection, ['softDelete' => false]);
328 $connection = $oldConnection;
329 }
330 else
331 {
332 $connection->setName($userData['userPrincipalName']);
333 $result = (new ConnectionManager())->update($connection);
334 if (!$result->isSuccess())
335 {
336 $connection->setName($currentName);
337 }
338 }
339 }
340 } catch (Exception $e) {
341 $connection->setName($currentName);
342 }
343 }
344 $this->accountName = $connection->getName();
345
346 return $connection;
347 }
348
356 private function getConnection(Role $owner, string $serviceName, string $name): ?Connection
357 {
358 try
359 {
360 return (new Core\Mappers\Connection())->getMap([
361 '=ENTITY_TYPE' => $owner->getType(),
362 '=ENTITY_ID' => $owner->getId(),
363 '=ACCOUNT_TYPE' => $serviceName,
364 '=NAME' => $name,
365 ])->fetch();
366 }
367 catch (BaseException|ArgumentException|SystemException $e)
368 {
369 return null;
370 }
371 }
372
380 private function rollBack(Connection $connection)
381 {
382 (new ConnectionManager())->disableConnection($connection);
383
384 NotificationManager::sendRollbackSyncNotification(
385 $connection->getOwner()->getId(),
386 $connection->getVendor()->getCode()
387 );
388 }
389
393 private function isPushEnabled(): bool
394 {
395 return CCalendar::IsBitrix24() || COption::GetOptionString('calendar', 'sync_by_push', false);
396 }
397}
static getConnectionContext(Connection $connection)
static addPullEvent(string $command, int $userId, array $params=[])
Definition util.php:373
addStatusHandler(callable $handler)