1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
OpenEventAttendeeService.php
См. документацию.
1<?php
2
3namespace Bitrix\Calendar\OpenEvents\Service;
4
5use Bitrix\Calendar\Access\ActionDictionary;
6use Bitrix\Calendar\Access\EventAccessController;
7use Bitrix\Calendar\Event\Service\OpenEventPullService;
8use Bitrix\Calendar\OpenEvents\Controller\Request\OpenEvent\SetEventAttendeeStatusDto;
9use Bitrix\Calendar\Core\Event\Event;
10use Bitrix\Calendar\Core\Mappers\Factory;
11use Bitrix\Calendar\Event\EventRepository;
12use Bitrix\Calendar\Integration;
13use Bitrix\Calendar\Internals\EventAttendee;
14use Bitrix\Calendar\Internals\EventAttendeeTable;
15use Bitrix\Calendar\Internals\Exception\PermissionDenied;
16use Bitrix\Calendar\OpenEvents\Dto\Category\PullEventUserFields;
17use Bitrix\Calendar\OpenEvents\Dto\Category\PullEventUserFieldsBuilder;
18use Bitrix\Calendar\OpenEvents\Exception\EventBusyException;
19use Bitrix\Calendar\OpenEvents\Exception\MaxAttendeesReachedException;
20use Bitrix\Calendar\OpenEvents\Internals\OpenEventOptionTable;
21use Bitrix\Main\Application;
22use Bitrix\Main\DB\Connection;
23use Bitrix\Main\DB\SqlExpression;
24use Bitrix\Main\DI\ServiceLocator;
25use Bitrix\Main\SystemException;
26use CCalendarEvent;
27
29{
30 private static ?self $instance;
31 private Factory $mapperFactory;
32
33 public static function getInstance(): self
34 {
35 self::$instance ??= new self();
36
37 return self::$instance;
38 }
39
45 public function setEventAttendeeStatus(int $userId, SetEventAttendeeStatusDto $setEventAttendeeStatusDto): void
46 {
47 $canAttend = EventAccessController::can(
48 $userId,
49 ActionDictionary::ACTION_OPEN_EVENT_ATTEND,
50 $setEventAttendeeStatusDto->eventId
51 );
52 if (!$canAttend)
53 {
54 throw new PermissionDenied();
55 }
56
57 $existEventAttendee = EventAttendeeTable::query()
58 ->addSelect('*', 'EVENT')
59 ->where('OWNER_ID', $userId)
60 ->where('EVENT_ID', $setEventAttendeeStatusDto->eventId)
61 ->fetchObject();
62 // if prev attendee status equals current, no need to go further
63 if (($existEventAttendee?->getMeetingStatus() === 'Y') === $setEventAttendeeStatusDto->attendeeStatus)
64 {
65 return;
66 }
67
68 $locker = Application::getConnection(EventAttendeeTable::getConnectionName());
69 $lockName = sprintf('open_event_attend_lock_%d', $setEventAttendeeStatusDto->eventId);
70
71 try
72 {
73 $isLocked = $locker->lock($lockName, 10);
74 if (!$isLocked)
75 {
76 throw new EventBusyException();
77 }
78
79 $eventMapper = $this->mapperFactory->getEvent();
81 $event = $eventMapper->getById($setEventAttendeeStatusDto->eventId);
82
83 $maxAttendees = $event->getEventOption()?->getOptions()?->maxAttendees ?? 0;
84
85 // check max count reach only while attend new user to event (increment attendee count)
86 if ($maxAttendees > 0 && $setEventAttendeeStatusDto->attendeeStatus)
87 {
88 $attendeesCount = EventRepository::getEventAttendeesCount($setEventAttendeeStatusDto->eventId);
89
90 if ($attendeesCount >= $event->getEventOption()->getOptions()->maxAttendees)
91 {
92 throw new MaxAttendeesReachedException();
93 }
94 }
95
96 $this->setAttendee($userId, $event, $setEventAttendeeStatusDto->attendeeStatus, $existEventAttendee);
97 }
98 finally
99 {
100 $locker->unlock($lockName);
101 }
102
103 $imIntegrationService = ServiceLocator::getInstance()->get(Integration\Im\EventCategoryServiceInterface::class);
104 $channelId = $event->getEventOption()->getCategory()->getChannelId();
105 if ($setEventAttendeeStatusDto->attendeeStatus && !$imIntegrationService->hasAccess($userId, $channelId))
106 {
107 $imIntegrationService->includeUserToChannel($userId, $channelId);
108 }
109
110 \CCalendar::ClearCache(['event_list']);
111 }
112
113 private function setAttendee(
114 int $userId,
115 Event $event,
116 bool $attendeeStatus,
117 ?EventAttendee $existEventAttendee = null
118 ): void
119 {
120 // TODO: need transaction?
122 $connection = Application::getInstance()->getConnection();
123 $connection->startTransaction();
124 $commited = false;
125
126 try
127 {
128 $meetingStatus = $attendeeStatus ? 'Y' : 'N';
129 if (!$existEventAttendee)
130 {
131 EventAttendeeTable::add([
132 'OWNER_ID' => $userId,
133 'CREATED_BY' => $userId,
134 'MEETING_STATUS' => $meetingStatus,
135 'EVENT_ID' => $event->getId(),
136 'SECTION_ID' => $event->getSection()->getId(),
137 'REMIND' => serialize(\CCalendarReminder::prepareReminder(
138 (new \Bitrix\Calendar\Core\Mappers\Event())->convertToArray($event)['REMIND'])
139 ),
140 ]);
141 }
142 else
143 {
144 $existEventAttendee->setDeleted(!$attendeeStatus);
145 $existEventAttendee->setMeetingStatus($meetingStatus);
146 $existEventAttendee->save();
147 }
148
149 $eventOptions = $event->getEventOption();
150 $increment = $attendeeStatus ? 1 : -1;
151 $incrementStr = $attendeeStatus ? '+ 1' : '- 1';
152
153 $updateResult = OpenEventOptionTable::update($eventOptions->getId(), [
154 'ATTENDEES_COUNT' => new SqlExpression('?# ' . $incrementStr, 'ATTENDEES_COUNT'),
155 ]);
156
157 if (!$updateResult->isSuccess())
158 {
159 // this rollback transaction and unlock entity for changes (in previous call)
160 throw new SystemException('failed to update event options');
161 }
162
163 $connection->commitTransaction();
164 $commited = true;
165
166 $eventOptions->setAttendeesCount($eventOptions->getAttendeesCount() + $increment);
167
168 OpenEventPullService::getInstance()->updateCalendarEvent(
169 event: $event,
170 userParams: [
171 $userId => PullEventUserFieldsBuilder::build(new PullEventUserFields(
172 isAttendee: $attendeeStatus,
173 )),
174 ],
175 );
176 }
177 finally
178 {
179 if (!$commited)
180 {
181 $connection->rollbackTransaction();
182 }
183 }
184
185 // update original event searchable content field
186 $this->updateEventSearchableContent($event);
187 }
188
189 private function __construct()
190 {
191 $this->mapperFactory = ServiceLocator::getInstance()->get('calendar.service.mappers.factory');
192 }
193
194 private function updateEventSearchableContent(Event $event): void
195 {
196 // this query need to fill static cache for attendees in CCalendarEvent
197 // it uses in next calls
198 $oldEvent = CCalendarEvent::GetList([
199 'checkPermission' => false,
200 'fetchAttendees' => true,
201 'arFilter' => [
202 'ID' => $event->getId(),
203 ],
204 ]);
205 $attendeeListData = CCalendarEvent::getAttendeeList([], [$event->getId()]);
206 $eventParams = [
207 'ID' => $event->getId(),
208 'NAME' => $event->getName(),
209 'DESCRIPTION' => $event->getDescription(),
210 'LOCATION' => $event->getLocation(),
211 'IS_MEETING' => true,
212 'ATTENDEE_LIST' => $attendeeListData['attendeeList'][$event->getId()] ?? [],
213 ];
215 params: [
216 'events' => [
217 $eventParams,
218 ],
219 ],
220 );
221 }
222}
$connection
Определения actionsdefinitions.php:38
if(empty( $fields)) foreach($fields as $field) $channelId
Определения push.php:23
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
Определения check_mail.php:18
static build(PullEventUserFields $pullEventUserFields)
Определения PullEventUserFieldsBuilder.php:9
static getAttendeeList($entryIdList=[], array $openEventIdList=[])
Определения calendar_event.php:1810
static GetList($params=[])
Определения calendar_event.php:830
static updateSearchIndex($eventIdList=[], $params=[])
Определения calendar_event.php:5996
static prepareReminder($reminder=[])
Определения calendar_reminder.php:431
$event
Определения prolog_after.php:141