ILIAS  trunk Revision v13.0_alpha-52-g21c366bbdd4
ControllerGUI.php
Go to the documentation of this file.
1<?php
2
20
29use ILIAS\components\OrgUnit\ARHelper\DIC;
32use ilUtil;
33
39{
40 use DIC;
41 public const FROM_URL = 'from_url';
42 public const OBSERVER_ID = 'observer_id';
43 public const SELECTED_OPTION = 'selected_option';
44 public const CMD_ABORT = 'abortBucket';
45 public const CMD_REMOVE = 'abortBucket';
46 public const CMD_USER_INTERACTION = 'userInteraction';
47 public const IS_ASYNC = 'bt_task_is_async';
48 public const CMD_GET_REPLACEMENT_ITEM = "getAsyncReplacementItem";
49
50 public function executeCommand(): void
51 {
52 $cmd = $this->ctrl()->getCmd();
53 switch ($cmd) {
56 break;
58 $this->userInteraction();
59 break;
60 case self::CMD_ABORT:
62 $this->abortBucket();
63 break;
64 default:
65 break;
66 }
67 }
68
69 public function getUnsafeGetCommands(): array
70 {
71 return array_unique([
72 self::CMD_ABORT,
73 self::CMD_REMOVE,
74 self::CMD_USER_INTERACTION,
75 ]);
76 }
77
78 public function getSafePostCommands(): array
79 {
80 return [];
81 }
82
83 protected function userInteraction(): void
84 {
85 $observer_id = $this->retrieveObserverIdFromRequest();
86 $selected_option = $this->retrieveSelectedInteractionOption();
87 if ($observer_id === null || $selected_option === null) {
89 }
90
91 $bucket = $this->dic()->backgroundTasks()->persistence()->loadBucket($observer_id);
92
94
95 $this->dic()->backgroundTasks()->taskManager()->continueTask(
96 $bucket,
97 new UserInteractionOption('', $selected_option)
98 );
99
101 }
102
103
104 protected function abortBucket(): void
105 {
106 $observer_id = $this->retrieveObserverIdFromRequest();
107 if ($observer_id === null) {
108 $this->respondWithError(StatusCode::HTTP_BAD_REQUEST, 'Bad Request');
109 }
110
111 $bucket = $this->dic()->backgroundTasks()->persistence()->loadBucket($observer_id);
112
113 $this->enforceBucketBelongsToCurrentUser($bucket);
114
115 $this->dic()->backgroundTasks()->taskManager()->quitBucket($bucket);
116
118 }
119
120
125 protected function getAsyncReplacementItem(): void
126 {
127 $observer_id = $this->retrieveObserverIdFromRequest();
128 if ($observer_id === null) {
129 $this->respondWithError(StatusCode::HTTP_BAD_REQUEST, 'Bad Request');
130 }
131
132 $bucket = $this->dic()->backgroundTasks()->persistence()->loadBucket($observer_id);
133
134 $this->enforceBucketBelongsToCurrentUser($bucket);
135
136 $item_source = new PopOverGUI($this->dic());
137 $this->dic()->language()->loadLanguageModule('background_tasks');
138 $item = $item_source->getItemForObserver($bucket);
139
140 $this->sendSuccessResponse(
142 $this->dic()->ui()->renderer()->renderAsync($item)
143 )
144 );
145 }
146
147
148 private function getFromURL(): URI
149 {
150 $uri = (new Factory())->uri($this->defaultReturnUrl());
151
152 $decoded_from_url = $this->retrieveFromUrlFromRequest();
153 if ($decoded_from_url === null || $decoded_from_url === '') {
154 return $uri;
155 }
156
157 $from_url = self::unhash($decoded_from_url);
158 if ($from_url === false) {
159 return $uri;
160 }
161
162 $from_url_parts = parse_url($from_url);
163 if (!is_array($from_url_parts)) {
164 return $uri;
165 }
166
167 $uri = $uri->withPath(null)->withQuery(null)->withFragment(null);
168
169 $mutators = [
170 'path' => static fn(URI $u, string $v): URI => $u->withPath($v),
171 'query' => static fn(URI $u, string $v): URI => $u->withQuery($v),
172 'fragment' => static fn(URI $u, string $v): URI => $u->withFragment($v),
173 ];
174
175 foreach ($mutators as $key => $apply) {
176 $value = $from_url_parts[$key] ?? null;
177 if (is_string($value) && $value !== '') {
178 $uri = $apply($uri, $value);
179 }
180 }
181
182 return $uri;
183 }
184
185 public static function hash(string $url): string
186 {
187 return base64_encode((string) $url);
188 }
189
190 public static function unhash(string $url): string|false
191 {
192 return base64_decode((string) $url);
193 }
194
195 private function enforceBucketBelongsToCurrentUser(Bucket $bucket): void
196 {
197 if ($bucket->getUserId() !== $this->user()->getId()) {
198 $this->respondWithError(StatusCode::HTTP_FORBIDDEN, 'Forbidden');
199 }
200 }
201
202 private function defaultReturnUrl(): string
203 {
204 return ilUtil::_getHttpPath();
205 }
206
207 private function sendSuccessResponse(Stream $stream): void
208 {
209 $response = $this->http()->response()
210 ->withStatus(StatusCode::HTTP_OK, 'OK')
211 ->withBody($stream);
212 $this->http()->saveResponse($response);
213
214 if ($this->wasInvokedAsynchronously()) {
215 $this->http()->sendResponse();
216 $this->http()->close();
217 }
218 }
219
220 private function redirectToCallerOrClose(): never
221 {
222 if (!$this->wasInvokedAsynchronously()) {
223 $this->ctrl()->redirectToURL((string) $this->getFromURL());
224 }
225
226 $this->http()->close();
227 }
228
229 private function respondWithError(int $error_status_code, string $message): never
230 {
231 $response = $this->http()->response()->withStatus($error_status_code, $message);
232 if ($error_status_code === StatusCode::HTTP_FORBIDDEN && !$this->wasInvokedAsynchronously()) {
233 $this->tpl()->setOnScreenMessage(
234 $this->tpl()::MESSAGE_TYPE_FAILURE,
235 $this->lng()->txt('permission_denied'),
236 true
237 );
239 ->withStatus(StatusCode::HTTP_FOUND, 'Found')
240 ->withHeader(ResponseHeader::LOCATION, $this->defaultReturnUrl());
241 }
242
243 $this->http()->saveResponse($response);
244 $this->http()->sendResponse();
245 $this->http()->close();
246 }
247
248 private function retrieveSelectedInteractionOption(): ?string
249 {
250 return $this->http()->wrapper()->query()->retrieve(
251 self::SELECTED_OPTION,
252 $this->dic()->refinery()->byTrying([
253 $this->dic()->refinery()->kindlyTo()->string(),
254 $this->dic()->refinery()->always(null)
255 ])
256 );
257 }
258
259 private function wasInvokedAsynchronously(): bool
260 {
261 return $this->http()->wrapper()->query()->retrieve(
262 self::IS_ASYNC,
263 $this->dic()->refinery()->byTrying([
264 $this->dic()->refinery()->kindlyTo()->bool(),
265 $this->dic()->refinery()->always(false)
266 ])
267 );
268 }
269
271 {
272 return $this->http()->wrapper()->query()->retrieve(
273 self::OBSERVER_ID,
274 $this->dic()->refinery()->byTrying([
275 $this->dic()->refinery()->kindlyTo()->int(),
276 $this->dic()->refinery()->always(null)
277 ])
278 );
279 }
280
281 private function retrieveFromUrlFromRequest(): ?string
282 {
283 return $this->http()->wrapper()->query()->retrieve(
284 self::FROM_URL,
285 $this->dic()->refinery()->byTrying([
286 $this->dic()->refinery()->kindlyTo()->string(),
287 $this->dic()->refinery()->always(null)
288 ])
289 );
290 }
291}
renderer()
getUnsafeGetCommands()
This method must return a list of unsafe GET commands.
respondWithError(int $error_status_code, string $message)
getAsyncReplacementItem()
Loads one single aggregate notification item representing a button async to replace an existing one.
getSafePostCommands()
This method must return a list of safe POST commands.
Builds data types.
Definition: Factory.php:36
The scope of this class is split ilias-conform URI's into components.
Definition: URI.php:35
withFragment(?string $fragment=null)
Get URI with modified fragment.
Definition: URI.php:315
withPath(?string $path=null)
Get URI with modified path.
Definition: URI.php:283
withQuery(?string $query=null)
Get URI with modified query.
Definition: URI.php:299
Stream factory which enables the user to create streams without the knowledge of the concrete class.
Definition: Streams.php:32
static ofString(string $string)
Creates a new stream with an initial value.
Definition: Streams.php:41
Util class various functions, usage as namespace.
static _getHttpPath()
Interface ResponseHeader.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static http()
Fetches the global http state from ILIAS.
$response
Definition: xapitoken.php:92