ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilChatroomViewGUI.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
26
34{
35 public function joinWithCustomName(): void
36 {
37 $this->redirectIfNoPermission('read');
38
39 $this->gui->switchToVisibleMode();
40 $this->setupTemplate();
41 $room = ilChatroom::byObjectId($this->gui->getObject()->getId());
42 $chat_user = new ilChatroomUser($this->ilUser, $room);
43 $failure = true;
44 $username = '';
45 $custom_username = false;
46
47 if ($this->hasRequestValue('custom_username_radio')) {
48 if (
49 $this->hasRequestValue('custom_username_text') &&
50 $this->getRequestValue('custom_username_radio', $this->refinery->kindlyTo()->string()) === 'custom_username'
51 ) {
52 $custom_username = true;
53 $username = $this->getRequestValue('custom_username_text', $this->refinery->kindlyTo()->string());
54 $failure = false;
55 } elseif (
56 method_exists(
57 $chat_user,
58 'build' . $this->getRequestValue('custom_username_radio', $this->refinery->kindlyTo()->string())
59 )
60 ) {
61 $username = $chat_user->{
62 'build' . $this->getRequestValue('custom_username_radio', $this->refinery->kindlyTo()->string())
63 }();
64 $failure = false;
65 }
66 }
67
68 if (!$failure && trim($username) !== '') {
69 if (!$room->isSubscribed($chat_user->getUserId())) {
70 $chat_user->setUsername($chat_user->buildUniqueUsername($username));
71 $chat_user->setProfilePictureVisible(!$custom_username);
72 }
73
74 $this->showRoom($room, $chat_user);
75 } else {
76 $this->mainTpl->setOnScreenMessage('failure', $this->ilLng->txt('no_username_given'));
77 $this->showNameSelection($chat_user);
78 }
79 }
80
84 private function setupTemplate(): void
85 {
86 ilLinkifyUtil::initLinkify($this->mainTpl);
87 $this->mainTpl->addJavaScript('assets/js/socket.io.min.js');
88 $this->mainTpl->addJavaScript('assets/js/Chatroom.min.js');
89 $this->mainTpl->addJavaScript('assets/js/AdvancedSelectionList.js');
90
91 $this->mainTpl->setPermanentLink($this->gui->getObject()->getType(), $this->gui->getObject()->getRefId());
92 }
93
97 private function showRoom(ilChatroom $room, ilChatroomUser $chat_user): void
98 {
99 $this->redirectIfNoPermission('read');
100
101 $user_id = $chat_user->getUserId();
102
103 $ref_id = $this->getRequestValue('ref_id', $this->refinery->kindlyTo()->int());
104 $this->navigationHistory->addItem(
105 $ref_id,
106 $this->ilCtrl->getLinkTargetByClass(ilRepositoryGUI::class, 'view'),
107 'chtr'
108 );
109
110 if ($room->isUserBanned($user_id)) {
111 $this->cancelJoin($this->ilLng->txt('banned'));
112 return;
113 }
114
115 $scope = $room->getRoomId();
116 $connector = $this->gui->getConnector();
117 $response = $connector->connect($scope, $user_id);
118
119 if (!$response) {
120 $this->mainTpl->setOnScreenMessage('failure', $this->ilLng->txt('unable_to_connect'), true);
121 $this->ilCtrl->redirectByClass(ilInfoScreenGUI::class, 'showSummary');
122 }
123
124 if (!$room->isSubscribed($chat_user->getUserId())) {
125 $room->connectUser($chat_user);
126 }
127
128 $response = $connector->sendEnterPrivateRoom($scope, $user_id);
129 if (!$response) {
130 $this->mainTpl->setOnScreenMessage('failure', $this->ilLng->txt('unable_to_connect'), true);
131 $this->ilCtrl->redirectByClass(ilInfoScreenGUI::class, 'showSummary');
132 }
133
134 $messages = $room->getSetting('display_past_msgs') ? array_reverse(array_filter(
135 $room->getLastMessages($room->getSetting('display_past_msgs'), $chat_user),
136 fn($entry) => $entry->type !== 'notice'
137 )) : [];
138
139 $is_moderator = ilChatroom::checkUserPermissions('moderate', $ref_id, false);
140 $show_auto_messages = !$this->ilUser->getPref('chat_hide_automsg_' . $room->getRoomId());
141
142 $build = $this->buildChat($room, $connector->getSettings());
143
144 $room_tpl = $build->template(false, $build->initialData(
145 $room->getConnectedUsers(),
146 $show_auto_messages,
147 $this->ilCtrl->getLinkTarget($this->gui, 'view-lostConnection', '', false),
148 [
149 'moderator' => $is_moderator,
150 'id' => $chat_user->getUserId(),
151 'login' => $chat_user->getUsername(),
152 'broadcast_typing' => $chat_user->enabledBroadcastTyping(),
153 'profile_picture_visible' => $chat_user->isProfilePictureVisible(),
154 ],
156 ), $this->panel($this->ilLng->txt('write_message'), $this->sendMessageForm()), $this->panel($this->ilLng->txt('messages'), $this->legacy('<div id="chat_messages"></div>')));
157
158 $this->mainTpl->setContent($room_tpl->get());
159 $this->mainTpl->setRightContent($this->userList() . $this->chatFunctions($show_auto_messages, $is_moderator));
160 }
161
162 public function readOnlyChatWindow(ilChatroom $room, array $messages): ilTemplate
163 {
164 $build = $this->buildChat($room, $this->gui->getConnector()->getSettings());
165
166 return $build->template(true, $build->initialData([], true, null, [
167 'moderator' => false,
168 'id' => -1,
169 'login' => null,
170 'broadcast_typing' => false,
171 ], $messages), $this->panel($this->ilLng->txt('messages'), $this->legacy('<div id="chat_messages"></div>')), '');
172 }
173
174 private function sendMessageForm(): Component
175 {
176 $template = new ilTemplate('tpl.chatroom_send_message_form.html', true, true, 'components/ILIAS/Chatroom');
177 $this->renderSendMessageBox($template);
178
179 return $this->legacy($template->get());
180 }
181
182 private function userList(): string
183 {
184 $roomRightTpl = new ilTemplate('tpl.chatroom_right.html', true, true, 'components/ILIAS/Chatroom');
185 $this->renderRightUsersBlock($roomRightTpl);
186
187 return $this->panel($this->ilLng->txt('users'), $this->legacy($roomRightTpl->get()));
188 }
189
190 private function chatFunctions(bool $show_auto_messages, bool $is_moderator): string
191 {
192 $txt = $this->ilLng->txt(...);
193 $js_escape = json_encode(...);
194 $format = fn($format, ...$args) => sprintf($format, ...array_map($js_escape, $args));
195 $register = fn($name, $c) => $c->withOnLoadCode(fn($id) => $format(
196 'il.Chatroom.bus.send(%s, document.getElementById(%s));',
197 $name,
198 $id
199 ));
200
201 $b = $this->uiFactory->button();
202 $toggle = fn($label, $enabled) => $b->toggle($label, '#', '#', $enabled)->withAriaLabel($label);
203
204 $bind = fn($key, $m) => $m->withAdditionalOnLoadCode(fn(string $id) => $format(
205 '$(() => il.Chatroom.bus.send(%s, {
206 node: document.getElementById(%s),
207 showModal: () => $(document).trigger(%s, {}),
208 closeModal: () => $(document).trigger(%s, {})
209 }));',
210 $key,
211 $id,
212 $m->getShowSignal()->getId(),
213 $m->getCloseSignal()->getId()
214 ));
215
216 $interrupt = fn($key, $label, $text, $button = null) => $bind($key, $this->uiFactory->modal()->interruptive(
217 $label,
218 $text,
219 ''
220 ))->withActionButtonLabel($button ?? $label);
221
222 $auto_scroll = $register('auto-scroll-toggle', $toggle($txt('auto_scroll'), true));
223 $messages = $register('system-messages-toggle', $toggle($txt('chat_show_auto_messages'), $show_auto_messages));
224
225 $invite = $bind('invite-modal', $this->uiFactory->modal()->roundtrip($txt('chat_invite'), $this->legacy($txt('invite_to_private_room')), [
226 $this->uiFactory->input()->field()->text($txt('chat_invite')),
227 ])->withSubmitLabel($txt('chat_invite')));
228
229 $buttons = [];
230 $buttons[] = $register('invite-button', $b->shy($txt('invite_to_private_room'), ''));
231 if ($is_moderator) {
232 $buttons[] = $register('clear-history-button', $b->shy($txt('clear_room_history'), ''));
233 }
234
235 return $this->panel($txt('chat_functions'), [
236 $this->legacy('<div id="chat_function_list">'),
237 ...$buttons,
238 $invite,
239 $interrupt('kick-modal', $txt('chat_kick'), $txt('kick_question')),
240 $interrupt('ban-modal', $txt('chat_ban'), $txt('ban_question')),
241 $interrupt('clear-history-modal', $txt('clear_room_history'), $txt('clear_room_history_question')),
242 $this->legacy('</div>'),
243 $this->legacy(sprintf('<div>%s%s</div>', $this->checkbox($auto_scroll), $this->checkbox($messages))),
244 ]);
245 }
246
247 private function checkbox(Component $component): string
248 {
249 return sprintf('<div class="chatroom-centered-checkboxes">%s</div>', $this->uiRenderer->render($component));
250 }
251
252 private function legacy(string $html): Component
253 {
254 return $this->uiFactory->legacy()->content($html);
255 }
256
260 private function panel(string $title, $body): string
261 {
262 if (is_array($body)) {
263 $body = $this->uiFactory->legacy()->content(join('', array_map($this->uiRenderer->render(...), $body)));
264 }
265 $panel = $this->uiFactory->panel()->secondary()->legacy($title, $body);
266
267 return $this->uiRenderer->render($panel);
268 }
269
270 public function toggleAutoMessageDisplayState(): void
271 {
272 $this->redirectIfNoPermission('read');
273
274 $room = ilChatroom::byObjectId($this->gui->getObject()->getId());
275
276 $state = 0;
277 if ($this->http->wrapper()->post()->has('state')) {
278 $state = $this->http->wrapper()->post()->retrieve('state', $this->refinery->kindlyTo()->int());
279 }
280
281 $this->ilUser->writePref(
282 'chat_hide_automsg_' . $room->getRoomId(),
283 (string) ((int) (!(bool) $state))
284 );
285
286 $this->http->saveResponse(
287 $this->http->response()
288 ->withHeader(ResponseHeader::CONTENT_TYPE, 'application/json')
289 ->withBody(Streams::ofString(json_encode(['success' => true], JSON_THROW_ON_ERROR)))
290 );
291 $this->http->sendResponse();
292 $this->http->close();
293 }
294
298 private function cancelJoin(string $message): void
299 {
300 $this->mainTpl->setOnScreenMessage('failure', $message);
301 }
302
303 protected function renderSendMessageBox(ilTemplate $roomTpl): void
304 {
305 $roomTpl->setVariable('PLACEHOLDER', $this->ilLng->txt('chat_osc_write_a_msg'));
306 $roomTpl->setVariable('LBL_SEND', $this->ilLng->txt('send'));
307 }
308
309 protected function renderRightUsersBlock(ilTemplate $roomTpl): void
310 {
311 $roomTpl->setVariable('LBL_NO_FURTHER_USERS', $this->ilLng->txt('no_further_users'));
312 }
313
314 private function showNameSelection(ilChatroomUser $chat_user): void
315 {
316 $name_options = $chat_user->getChatNameSuggestions();
317 $formFactory = new ilChatroomFormFactory();
318 $selectionForm = $formFactory->getUserChatNameSelectionForm($name_options);
319
320 $this->ilCtrl->saveParameter($this->gui, 'sub');
321
322 $selectionForm->addCommandButton('view-joinWithCustomName', $this->ilLng->txt('enter'));
323 $selectionForm->setFormAction(
324 $this->ilCtrl->getFormAction($this->gui, 'view-joinWithCustomName')
325 );
326
327 $this->mainTpl->setVariable('ADM_CONTENT', $selectionForm->getHTML());
328 }
329
336 public function executeDefault(string $requestedMethod): void
337 {
338 $this->redirectIfNoPermission('read');
339
340 $this->gui->switchToVisibleMode();
341 $this->setupTemplate();
342
343 $chatSettings = new ilSetting('chatroom');
344 if (!$chatSettings->get('chat_enabled', '0')) {
345 $this->ilCtrl->redirect($this->gui, 'settings-general');
346 }
347
348 $room = ilChatroom::byObjectId($this->gui->getObject()->getId());
349
350 if (!$room->getSetting('allow_anonymous') && $this->ilUser->isAnonymous()) {
351 $this->cancelJoin($this->ilLng->txt('chat_anonymous_not_allowed'));
352 return;
353 }
354
355 $chat_user = new ilChatroomUser($this->ilUser, $room);
356
357 if ($room->getSetting('allow_custom_usernames')) {
358 if ($room->isSubscribed($chat_user->getUserId())) {
359 $chat_user->setUsername($chat_user->getUsername());
360 $this->showRoom($room, $chat_user);
361 } else {
362 $this->showNameSelection($chat_user);
363 }
364 } else {
365 $chat_user->setUsername($this->ilUser->getPublicName());
366 $chat_user->setProfilePictureVisible(true);
367 $this->showRoom($room, $chat_user);
368 }
369 }
370
371 public function logout(): void
372 {
373 $pid = $this->tree->getParentId($this->gui->getRefId());
374 $this->ilCtrl->setParameterByClass(ilRepositoryGUI::class, 'ref_id', $pid);
375 $this->ilCtrl->redirectByClass(ilRepositoryGUI::class);
376 }
377
378 public function lostConnection(): void
379 {
380 if ($this->http->wrapper()->query()->has('msg')) {
381 match ($this->http->wrapper()->query()->retrieve('msg', $this->refinery->kindlyTo()->string())) {
382 'kicked' => $this->mainTpl->setOnScreenMessage('failure', $this->ilLng->txt('kicked'), true),
383 'banned' => $this->mainTpl->setOnScreenMessage('failure', $this->ilLng->txt('banned'), true),
384 default => $this->mainTpl->setOnScreenMessage('failure', $this->ilLng->txt('lost_connection'), true),
385 };
386 } else {
387 $this->mainTpl->setOnScreenMessage('failure', $this->ilLng->txt('lost_connection'), true);
388 }
389
390 $this->ilCtrl->redirectByClass(ilInfoScreenGUI::class, 'showSummary');
391 }
392
393 public function getUserProfileImages(): void
394 {
395 global $DIC;
396
397 $response = [];
398
399 $request = json_decode($this->http->request()->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
400
402
403 $users = $this->refinery->kindlyTo()->listOf($this->refinery->byTrying([
404 $this->refinery->kindlyTo()->recordOf([
405 'id' => $this->refinery->kindlyTo()->int(),
406 'username' => $this->refinery->kindlyTo()->string(),
407 'profile_picture_visible' => $this->refinery->kindlyTo()->bool(),
408 ]),
409 $this->refinery->kindlyTo()->recordOf([
410 'id' => $this->refinery->kindlyTo()->int(),
411 'username' => $this->refinery->kindlyTo()->string(),
412 ]),
413 ]))->transform($request['profiles'] ?? []);
414
415 $user_ids = array_column($users, 'id');
416
417 $public_data = ilUserUtil::getNamePresentation($user_ids, true, false, '', false, true, false, true);
418
419 foreach ($users as $user) {
420 if ($user['profile_picture_visible'] ?? false) {
421 $public_image = $public_data[$user['id']]['img'] ?? '';
422 } else {
424 $avatar = $DIC["user.avatar.factory"]->avatar('xsmall');
425 $avatar->setUsrId(ANONYMOUS_USER_ID);
426 $avatar->setName(ilStr::subStr($user['username'], 0, 2));
427 $public_image = $avatar->getUrl();
428 }
429
430 $response[json_encode($user, JSON_THROW_ON_ERROR)] = $public_image;
431 }
432
433 $this->sendJSONResponse($response);
434 }
435
436 public function userEntry(): void
437 {
438 global $DIC;
439
440 $kindly = $this->refinery->kindlyTo();
441 $s = $kindly->string();
442 $int = $kindly->int();
443 $get = $this->http->wrapper()->query()->retrieve(...);
444 $get_or = fn($k, $t, $d = null) => $get($k, $this->refinery->byTrying([$t, $this->refinery->always($d)]));
445
446 $ref_id = $get('ref_id', $int);
447 $user_id = $get('user_id', $int);
448 $username = $get('username', $s);
449 $actions = $get_or('actions', $kindly->dictOf($s), []);
450
451 $avatar = $DIC["user.avatar.factory"]->avatar('xsmall');
452 $avatar->setUsrId(ANONYMOUS_USER_ID);
453 $avatar->setName(ilStr::subStr($username, 0, 2));
454 $public_image = $avatar->getUrl();
455 $item = $this->uiFactory->item()->standard($username)->withLeadImage($this->uiFactory->image()->standard(
456 $public_image,
457 'Profile image of ' . $username
458 ));
459
461 $item = $item->withProperties([
462 $this->ilLng->txt('role') => $this->ilLng->txt('il_chat_moderator'),
463 ]);
464 }
465 $item = $item->withActions($this->uiFactory->dropdown()->standard($this->buildUserActions($user_id, $actions)));
466
467
468 $this->sendResponse($this->uiRenderer->renderAsync($item), 'text/html');
469 }
470
475 private function buildUserActions(int $user_id, array $actions): array
476 {
477 $chat_settings = new ilSetting('chatroom');
478 $osc_enabled = $chat_settings->get('chat_enabled') && $chat_settings->get('enable_osc');
479 $translations = [
480 'kick' => $this->ilLng->txt('chat_kick'),
481 'ban' => $this->ilLng->txt('chat_ban'),
482 ];
483
484 if ($osc_enabled && ilObjUser::_lookupPref($user_id, 'chat_osc_accept_msg') === 'y') {
485 $translations['chat'] = $this->ilLng->txt('start_private_chat');
486 }
487
488 $buttons = [];
489 foreach ($actions as $key => $bus_id) {
490 $label = $translations[$key] ?? false;
491 if ($label) {
492 $buttons[] = $this->uiFactory->button()->shy($label, '')->withAdditionalOnLoadCode(fn(string $id): string => (
493 'il.Chatroom.bus.send(' . json_encode(
494 $bus_id,
495 JSON_THROW_ON_ERROR
496 ) . ', document.getElementById(' . json_encode($id, JSON_THROW_ON_ERROR) . '));'
497 ));
498 }
499 }
500
501 return $buttons;
502 }
503
504 private function buildChat(ilChatroom $room, ilChatroomServerSettings $settings): BuildChat
505 {
506 return new BuildChat($this->ilCtrl, $this->ilLng, $this->gui, $room, $settings, $this->ilUser, $this->uiFactory, $this->uiRenderer);
507 }
508}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
setVariable($variable, $value='')
Sets a variable value.
Definition: IT.php:544
Stream factory which enables the user to create streams without the knowledge of the concrete class.
Definition: Streams.php:32
Class ilChatroomGUIHandler.
redirectIfNoPermission($permission)
Checks for requested permissions and redirects if the permission check failed.
getRequestValue(string $key, Transformation $trafo, $default=null)
Class ilChatroomServerSettings.
Class ilChatroomUser.
getChatNameSuggestions()
Returns an array of chat-name suggestions.
getUserId()
Returns Ilias User ID.
getUsername()
Returns username from Object or SESSION.
Class ilChatroomViewGUI.
readOnlyChatWindow(ilChatroom $room, array $messages)
buildChat(ilChatroom $room, ilChatroomServerSettings $settings)
panel(string $title, $body)
renderRightUsersBlock(ilTemplate $roomTpl)
cancelJoin(string $message)
Calls ilUtil::sendFailure method using given $message as parameter.
checkbox(Component $component)
setupTemplate()
Adds CSS and JavaScript files that should be included in the header.
showNameSelection(ilChatroomUser $chat_user)
buildUserActions(int $user_id, array $actions)
executeDefault(string $requestedMethod)
Chatroom and Chatuser get prepared before $this->showRoom method is called.
chatFunctions(bool $show_auto_messages, bool $is_moderator)
showRoom(ilChatroom $room, ilChatroomUser $chat_user)
Prepares and displays chatroom and connects user to it.
renderSendMessageBox(ilTemplate $roomTpl)
Class ilChatroom.
getConnectedUsers(bool $only_data=true)
static checkPermissionsOfUser(int $usr_id, $permissions, int $ref_id)
Checks user permissions in question for a given user id in relation to a given ref_id.
connectUser(ilChatroomUser $user)
static checkUserPermissions($permissions, int $ref_id, bool $send_info=true)
Checks user permissions by given array and ref_id.
getSetting(string $name)
isUserBanned(int $user_id)
isSubscribed(int $chat_userid)
getLastMessages(int $number, ilChatroomUser $chatuser)
static byObjectId(int $object_id)
Class ilCtrl provides processing control methods.
redirectByClass( $a_class, ?string $a_cmd=null, ?string $a_anchor=null, bool $is_async=false)
@inheritDoc
getFormAction(object $a_gui_obj, ?string $a_fallback_cmd=null, ?string $a_anchor=null, bool $is_async=false, bool $has_xml_style=false)
@inheritDoc
saveParameter(object $a_gui_obj, $a_parameter)
@inheritDoc
redirect(object $a_gui_obj, ?string $a_cmd=null, ?string $a_anchor=null, bool $is_async=false)
@inheritDoc
setParameterByClass(string $a_class, string $a_parameter, $a_value)
@inheritDoc
getLinkTargetByClass( $a_class, ?string $a_cmd=null, ?string $a_anchor=null, bool $is_async=false, bool $has_xml_style=false)
@inheritDoc
static initLinkify(?ilGlobalTemplateInterface $a_tpl=null)
static _lookupPref(int $a_usr_id, string $a_keyword)
ILIAS Setting Class.
static subStr(string $a_str, int $a_start, ?int $a_length=null)
Definition: class.ilStr.php:21
special template class to simplify handling of ITX/PEAR
static getNamePresentation( $a_user_id, bool $a_user_image=false, bool $a_profile_link=false, string $a_profile_back_link='', bool $a_force_first_lastname=false, bool $a_omit_login=false, bool $a_sortable=true, bool $a_return_data_array=false, $a_ctrl_path=null)
Default behaviour is:
static setTokenMaxLifetimeInSeconds(int $token_max_lifetime_in_seconds)
const ANONYMOUS_USER_ID
Definition: constants.php:27
$c
Definition: deliver.php:25
$txt
Definition: error.php:31
Interface ResponseHeader.
This describes commonalities between standard and primary buttons.
Definition: Button.php:34
A component is the most general form of an entity in the UI.
Definition: Component.php:28
$ref_id
Definition: ltiauth.php:66
$scope
Definition: ltiregstart.php:51
static http()
Fetches the global http state from ILIAS.
global $DIC
Definition: shib_login.php:26
$messages
Definition: xapiexit.php:21
$message
Definition: xapiexit.php:31
$response
Definition: xapitoken.php:93