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