1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
startsynccontroller.php
См. документацию.
1<?php
2
3namespace Bitrix\Calendar\Sync\Office365;
4
5use Bitrix\Calendar\Core;
6use Bitrix\Calendar\Core\Base\BaseException;
7use Bitrix\Calendar\Core\Role\Role;
8use Bitrix\Calendar\Core\Role\User;
9use Bitrix\Calendar\Integration\Pull\PushCommand;
10use Bitrix\Calendar\Sync\Util\HandleStatusTrait;
11use Bitrix\Calendar\Sync;
12use Bitrix\Calendar\Sync\Connection\Connection;
13use Bitrix\Calendar\Sync\Exceptions\SyncException;
14use Bitrix\Calendar\Sync\Factories\SyncSectionFactory;
15use Bitrix\Calendar\Sync\Managers\ConnectionManager;
16use Bitrix\Calendar\Sync\Managers\NotificationManager;
17use Bitrix\Calendar\Sync\Managers\OutgoingManager;
18use Bitrix\Calendar\Sync\Managers\StartSynchronization;
19use Bitrix\Calendar\Sync\Managers\VendorDataExchangeManager;
20use Bitrix\Calendar\Sync\Util\Result;
21use Bitrix\Calendar\Util;
22use Bitrix\Dav\Internals\DavConnectionTable;
23use Bitrix\Main\ArgumentException;
24use Bitrix\Main\Error;
25use Bitrix\Main\LoaderException;
26use Bitrix\Main\ObjectNotFoundException;
27use Bitrix\Main\ObjectPropertyException;
28use Bitrix\Main\SystemException;
29use CCalendar;
30use COption;
31use Exception;
32use Psr\Container\NotFoundExceptionInterface;
33use Throwable;
34
36{
37 use HandleStatusTrait;
38
39 private const STATUSES = [
40 'connection_created' => 'connection_created',
41 'connection_renamed' => 'connection_renamed',
42 'sections_sync_finished' => 'sections_sync_finished',
43 'events_sync_finished' => 'events_sync_finished',
44 'subscribe_finished' => 'subscribe_finished',
45 'all_finished' => 'all_finished',
46 'export_finished' => 'export_finished',
47 ];
48
52 private string $accountName = '';
56 private Role $owner;
57
61 public function __construct(Role $owner)
62 {
63 $this->owner = $owner;
64 }
65
72 public function synchronize(): array
73 {
74 $response = [
75 'status' => 'success',
76 'message' => 'CONNECTION_CREATED'
77 ];
78
79 $owner = \Bitrix\Calendar\Core\Role\Helper::getRole(\CCalendar::GetUserId(), User::TYPE);
80 $pusher = static function ($result) use ($owner)
81 {
83 PushCommand::ProcessSyncConnection,
84 $owner->getId(),
86 );
87
88 if ($result['stage'] === self::STATUSES['export_finished'])
89 {
90 NotificationManager::addFinishedSyncNotificationAgent(
91 $owner->getId(),
92 $result['vendorName']
93 );
94 }
95 };
96
97 try
98 {
99 // start process
100 if ($connection = $this->addStatusHandler($pusher)->start())
101 {
102 $response['connectionId'] = $connection->getId();
103 }
104 else
105 {
106 $response['connectionId'] = null;
107 }
108 }
109 catch (\Throwable $e)
110 {
111 $response = [
112 'status' => 'error',
113 'message' => 'Could not finish sync: '.$e->getMessage()
114 ];
115 }
116
117 return $response;
118 }
119
129 public function start(): ?Connection
130 {
132 if ($connection = $this->initConnection())
133 {
134 // TODO: change it to disabling update sections agent
135 $this->muteConnection($connection, true);
136 $status = self::STATUSES['connection_created'];
137 try
138 {
139 $connection = $this->fixUglyAccountName($connection);
140 $this->sendResult($status);
141 // $status = self::STATUSES['connection_renamed']; // this status is virtual. We can't roll back it.
142
143 $factory = new Factory($connection);
144
145 $exchangeManager = new VendorDataExchangeManager(
146 $factory,
147 (new SyncSectionFactory())->getSyncSectionMapByFactory($factory)
148 );
149
150 $exchangeManager
151 ->addStatusHandlerList($this->getStatusHandlerList())
152 ->exchange();
153
154 $status = self::STATUSES['export_finished'];
155 $this->sendResult($status);
156
157 if ($this->isPushEnabled())
158 {
159 $this->initSubscription($connection);
160// $status = self::STATUSES['subscribe_finished'];
161// $this->sendResult($status);
162 }
163
164 $this->setConnectionStatus($connection, Sync\Dictionary::SYNC_STATUS['success']);
165
166 $this->muteConnection($connection, false);
167 return $connection;
168 }
169 catch (SyncException|Throwable $e)
170 {
171 // TODO: remove Throwable after finish of testing
172 $this->rollBack($connection);
173 throw $e;
174 }
175 }
176
177 throw new SyncException('Error of create connection');
178 }
179
186 private function muteConnection(Connection $connection, bool $state)
187 {
188 $original = $connection->isDeleted();
189 $connection->setDeleted($state);
190 (new Core\Mappers\Connection())->update($connection);
191 $connection->setDeleted($original);
192 }
193
197 private function initConnection(): ?Connection
198 {
199 $connectionManager = new ConnectionManager();
200 $connections = $connectionManager->getConnectionsData($this->owner, [Helper::ACCOUNT_TYPE]);
201 $connectionManager->deactivateConnections($connections);
202
203 $result = $connectionManager->initConnection(
204 $this->owner,
205 Helper::ACCOUNT_TYPE,
206 Helper::SERVER_PATH,
207 );
208 if ($result->isSuccess())
209 {
210 return $result->getData()['connection'];
211 }
212
213 return null;
214 }
215
221 private function sendResult(string $stage)
222 {
223 $this->sendStatus([
224 'vendorName' => Helper::ACCOUNT_TYPE,
225 'accountName' => $this->getAccountName(),
226 'stage' => $stage,
227 ]);
228 }
229
233 private function getAccountName(): string
234 {
235 return $this->accountName ?? '';
236 }
237
238 private array $outgoingManagersCache = [];
246 private function getOutgoingManager(Connection $connection)
247 {
248
249 if (empty($this->outgoingManagersCache[$connection->getId()]))
250 {
251 $this->outgoingManagersCache[$connection->getId()] = new OutgoingManager($connection);
252 }
253
254 return $this->outgoingManagersCache[$connection->getId()];
255 }
256
262 private function initSubscription(Connection $connection): Result
263 {
264 $result = new Result();
265 try
266 {
267 $links = (new Core\Mappers\SectionConnection())->getMap([
268 '=CONNECTION_ID' => $connection->getId(),
269 '=ACTIVE' => 'Y'
270 ]);
271 $manager = $this->getOutgoingManager($connection);
272 foreach ($links as $link)
273 {
274 try
275 {
276 $manager->subscribeSection($link);
277 }
278 catch (Exception $e)
279 {
280 $result->addError(new Error($e->getMessage(), $e->getCode()));
281 }
282 }
283 }
284 catch (Exception $e)
285 {
286 $result->addError(new Error($e->getMessage(), $e->getCode()));
287 }
288
289 return $result;
290 }
291
300 private function setConnectionStatus(Connection $connection, string $status)
301 {
302 DavConnectionTable::update($connection->getId(), [
303 'LAST_RESULT' => $status,
304 ]);
305 }
306
314 private function fixUglyAccountName(Connection $connection): Connection
315 {
316 if (substr($connection->getName(), 0,9) === 'Office365')
317 {
318 $currentName = $connection->getName();
319 try {
321 $userData = $context->getApiClient()->get('me');
322 if (!empty($userData['userPrincipalName']))
323 {
324 if ($oldConnection = $this->getConnection(
325 $connection->getOwner(),
326 Helper::ACCOUNT_TYPE,
327 $userData['userPrincipalName']
328 ))
329 {
330 $oldConnection->setDeleted(false);
331 (new Core\Mappers\Connection())->delete($connection, ['softDelete' => false]);
332 $connection = $oldConnection;
333 }
334 else
335 {
336 $connection->setName($userData['userPrincipalName']);
337 $result = (new ConnectionManager())->update($connection);
338 if (!$result->isSuccess())
339 {
340 $connection->setName($currentName);
341 }
342 }
343 }
344 } catch (Exception $e) {
345 $connection->setName($currentName);
346 }
347 }
348 $this->accountName = $connection->getName();
349
350 return $connection;
351 }
352
360 private function getConnection(Role $owner, string $serviceName, string $name): ?Connection
361 {
362 try
363 {
364 return (new Core\Mappers\Connection())->getMap([
365 '=ENTITY_TYPE' => $owner->getType(),
366 '=ENTITY_ID' => $owner->getId(),
367 '=ACCOUNT_TYPE' => $serviceName,
368 '=NAME' => $name,
369 ])->fetch();
370 }
371 catch (BaseException|ArgumentException|SystemException $e)
372 {
373 return null;
374 }
375 }
376
384 private function rollBack(Connection $connection)
385 {
386 (new ConnectionManager())->disableConnection($connection);
387
388 NotificationManager::sendRollbackSyncNotification(
389 $connection->getOwner()->getId(),
390 $connection->getVendor()->getCode()
391 );
392 }
393
397 private function isPushEnabled(): bool
398 {
399 return CCalendar::IsBitrix24() || COption::GetOptionString('calendar', 'sync_by_push', false);
400 }
401}
$connection
Определения actionsdefinitions.php:38
static getRole(int $id, string $type)
Определения helper.php:17
const SYNC_STATUS
Определения dictionary.php:16
static getConnectionContext(Connection $connection)
Определения office365context.php:62
static addPullEvent(PushCommand $command, int $userId, array $params=[])
Определения util.php:385
static GetOptionString($module_id, $name, $def="", $site=false, $bExactSite=false)
Определения option.php:8
static IsBitrix24()
Определения calendar.php:1443
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$result
Определения get_property_values.php:14
$context
Определения csv_new_setup.php:223
$status
Определения session.php:10
$name
Определения menu_edit.php:35
sendStatus($status)
Определения handlestatustrait.php:50
trait Error
Определения error.php:11
$manager
Определения office365push.php:39
$response
Определения result.php:21