ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.ilResourceCollectionGUI.php
Go to the documentation of this file.
1 <?php
2 
37 
42 {
44 
45  public const P_RESOURCE_ID = 'resource_id';
46  public const P_RESOURCE_IDS = 'resource_ids';
47 
48  public const CMD_INDEX = 'index';
49  public const CMD_INFO = 'info';
50  public const CMD_UPLOAD = 'upload';
51  public const CMD_POST_UPLOAD = 'postUpload';
52  public const CMD_REMOVE = 'remove';
53  public const CMD_DOWNLOAD = 'download';
54 
55  public const CMD_UNZIP = 'unzip';
56  public const CMD_EDIT = 'rename';
57  public const CMD_RENDER_CONFIRM_REMOVE = 'renderConfirmRemove';
58  public const CMD_STORE = 'store';
63  private \ILIAS\UI\Renderer $ui_renderer;
64  private \ILIAS\Refinery\Factory $refinery;
65  private \ILIAS\HTTP\Services $http;
67  private \ILIAS\ResourceStorage\Services $irss;
70  private \ILIAS\UI\Factory $ui_factory;
71  private \ILIAS\FileUpload\FileUpload $upload;
72  private \ILIAS\Filesystem\Util\Archive\Archives $archive;
74 
75  final public function __construct(
76  private Configuration $view_configuration
77  ) {
78  global $DIC;
79  $this->ctrl = $DIC->ctrl();
80  $this->main_tpl = $DIC->ui()->mainTemplate();
81  $this->ui_renderer = $DIC->ui()->renderer();
82  $this->ui_factory = $DIC->ui()->factory();
83  $this->http = $DIC->http();
84  $this->refinery = $DIC->refinery();
85  $this->language = $DIC->language();
86  $this->language->loadLanguageModule('irss');
87  $this->irss = $DIC->resourceStorage();
88  $this->upload = $DIC->upload();
89  $this->archive = $DIC->archives();
90  $this->preview_definition = new PreviewDefinition();
91 
92  $this->view_request = new Request(
93  $DIC->ctrl(),
94  $DIC->http()->wrapper()->query(),
95  $this->view_configuration
96  );
97 
98  $data_provider = new TableDataProvider($this->view_request);
99 
100  $this->action_builder = new ActionBuilder(
101  $this->view_request,
102  $this->ctrl,
103  $DIC->ui()->factory(),
104  $DIC->language(),
106  );
107 
108  $view_control_builder = new ViewControlBuilder(
109  $this->view_request,
110  $data_provider,
111  $this->ctrl,
112  $DIC->ui()->factory(),
113  $DIC->language()
114  );
115 
116  $upload_builder = new UploadBuilder(
117  $this->view_request,
118  $this->ctrl,
119  $DIC->ui()->factory(),
120  $DIC->language(),
121  $this
122  );
123 
124  $this->view_factory = new ViewFactory(
125  $data_provider,
126  $this->action_builder,
127  $view_control_builder,
128  $upload_builder
129  );
130  }
131 
132  // CMD CLASS
133 
139  {
140  $rid = $this->getResourceIdsFromRequest()[0] ?? null;
141  if ($rid === null || !$this->view_request->getCollection()->isIn($rid)) {
142  $this->abortWithPermissionDenied();
143  }
144  return $rid;
145  }
146 
147  protected function abortWithPermissionDenied(): void
148  {
149  $this->main_tpl->setOnScreenMessage('failure', $this->language->txt('msg_no_perm_read'), true);
150  $this->ctrl->redirect($this, self::CMD_INDEX);
151  }
152 
153  final public function executeCommand(): void
154  {
155  if ($this->view_request->handleViewTitle()) {
156  $title = $this->view_request->getTitle();
157  if ($title !== null) {
158  $this->main_tpl->setTitle($title);
159  }
160  $description = $this->view_request->getDescription();
161  if ($description !== null) {
162  $this->main_tpl->setDescription($description);
163  }
164  }
165 
166  $this->view_request->init($this);
167 
168  switch ($this->ctrl->getCmd(self::CMD_INDEX)) {
169  case self::CMD_INDEX:
170  $this->index();
171  break;
172  case self::CMD_UPLOAD:
173  $this->upload();
174  break;
175  case self::CMD_POST_UPLOAD:
176  $this->postUpload();
177  break;
178  case self::CMD_REMOVE:
179  $this->remove();
180  break;
181  case self::CMD_DOWNLOAD:
182  $this->download();
183  break;
184  case self::CMD_UNZIP:
185  $this->unzip();
186  break;
187  case self::CMD_RENDER_CONFIRM_REMOVE:
188  $this->renderConfirmRemove();
189  break;
190  case self::CMD_EDIT:
191  $this->edit();
192  break;
193  case self::CMD_STORE:
194  $this->store();
195  break;
196  }
197  }
198 
199  // RESOURCE COLLECTION GUI
200 
201  private function index(): void
202  {
203  $provider = $this->view_factory->getComponentProvider($this->view_request);
204  $components = [];
205  foreach ($provider->getComponents() as $component) {
206  $components[] = $component;
207  }
208 
209  $this->main_tpl->setContent($this->ui_renderer->render($components));
210  }
211 
212  public function upload(): void
213  {
214  if (!$this->view_request->canUserUplaod()) {
215  $this->abortWithPermissionDenied();
216  return;
217  }
218  $this->upload->process();
219  if (!$this->upload->hasUploads()) {
220  return;
221  }
222  $collection = $this->view_request->getCollection();
223  foreach ($this->upload->getResults() as $result) {
224  if (!$result->isOK()) {
225  continue;
226  }
227  $rid = $this->irss->manage()->upload(
228  $result,
229  $this->view_configuration->getStakeholder()
230  );
231  $collection->add($rid);
232 
233  // ensure flavour
234  $this->irss->flavours()->ensure(
235  $rid,
236  $this->preview_definition
237  );
238  }
239  $this->irss->collection()->store($collection);
240  $upload_result = new BasicHandlerResult(
241  self::P_RESOURCE_ID,
242  BasicHandlerResult::STATUS_OK,
243  $rid->serialize(),
244  ''
245  );
246  $response = $this->http->response()->withBody(Streams::ofString(json_encode($upload_result)));
247  $this->http->saveResponse($response);
248  $this->http->sendResponse();
249  $this->http->close();
250  }
251 
252  private function postUpload(): void
253  {
254  if (!$this->view_request->canUserUplaod()) {
255  $this->abortWithPermissionDenied();
256  return;
257  }
258  $this->main_tpl->setOnScreenMessage('success', $this->language->txt('rids_appended'), true);
259  $this->ctrl->redirect($this, self::CMD_INDEX);
260  }
261 
262  private function download(): void
263  {
264  $rid = $this->checkResourceOrRedirect();
265  $this->irss->consume()->download($rid)->run();
266  }
267 
268  private function unzip(): void
269  {
270  if (!$this->view_request->canUserAdministrate()) {
271  $this->abortWithPermissionDenied();
272  return;
273  }
274  $rid = $this->checkResourceOrRedirect();
275  $zip_stream = $this->irss->consume()->stream($rid)->getStream();
276 
277  $collection = $this->view_request->getCollection();
278 
279  $unzip_options = $this->archive->unzipOptions()
280  ->withDirectoryHandling(ZipDirectoryHandling::FLAT_STRUCTURE);
281 
282  foreach ($this->archive->unzip($zip_stream, $unzip_options)->getFileStreams() as $stream) {
283  $rid = $this->irss->manage()->stream(
284  Streams::ofString($stream->getContents()),
285  $this->view_configuration->getStakeholder(),
286  basename($stream->getMetadata()['uri'])
287  );
288  $collection->add($rid);
289 
290  // ensure flavour
291  try {
292  $this->irss->flavours()->ensure(
293  $rid,
294  $this->preview_definition
295  );
296  } catch (\Throwable $e) {
297  }
298  }
299  $this->irss->collection()->store($collection);
300  $this->postUpload();
301  }
302 
303  private function edit(): void
304  {
305  if (!$this->view_request->canUserAdministrate()) {
306  $this->abortWithPermissionDenied();
307  return;
308  }
309  $rid = $this->checkResourceOrRedirect();
310  $this->ctrl->setParameter(
311  $this,
312  self::P_RESOURCE_ID,
313  $this->hash($rid->serialize())
314  );
315 
316  // build simple form
317  $form = new EditForm(
318  $this->view_request,
319  $rid
320  );
321 
322  $modal = $this->ui_factory->modal()->roundtrip(
323  $this->language->txt('edit'),
324  null,
325  $form->getFields(),
326  $this->ctrl->getLinkTarget($this, self::CMD_STORE)
327  );
328 
329  $signal = $modal->getForm()->getSubmitSignal();
330 
331  $stream = Streams::ofString(
332  $this->ui_renderer->renderAsync(
333  $modal
334  )
335  );
336 
337  $this->http->saveResponse($this->http->response()->withBody($stream));
338  $this->http->sendResponse();
339  $this->http->close();
340  }
341 
342  private function store(): void
343  {
344  if (!$this->view_request->canUserAdministrate()) {
345  $this->abortWithPermissionDenied();
346  return;
347  }
348  $rid = $this->checkResourceOrRedirect();
349  $form = (new EditForm(
350  $this->view_request,
351  $rid
352  ))->getAsForm($this->ctrl->getLinkTarget($this, self::CMD_STORE))
353  ->withRequest(
354  $this->http->request()
355  );
356  // Store the data
357  $form->getData();
358  $this->main_tpl->setOnScreenMessage('success', $this->language->txt('rids_updated'), true);
359  $this->ctrl->redirect($this, self::CMD_INDEX);
360  }
361 
362  private function renderConfirmRemove(): void
363  {
364  if (!$this->view_request->canUserAdministrate()) {
365  $this->abortWithPermissionDenied();
366  return;
367  }
368  $rids = $this->getResourceIdsFromRequest();
369  $stream = Streams::ofString(
370  $this->ui_renderer->render(
371  $this->ui_factory->modal()->interruptive(
372  $this->language->txt('action_remove_resource'),
373  $this->language->txt('action_remove_resource_msg'),
374  $this->ctrl->getLinkTarget($this, self::CMD_REMOVE)
375  )->withAffectedItems(
376  array_map(function (ResourceIdentification $rid) {
377  $revision = $this->irss->manage()->getCurrentRevision($rid);
378 
379  return $this->ui_factory->modal()->interruptiveItem()->standard(
380  $this->hash($rid->serialize()),
381  $revision->getTitle()
382  );
383  }, $rids)
384  )
385  )
386  );
387  $this->http->saveResponse($this->http->response()->withBody($stream));
388  $this->http->sendResponse();
389  $this->http->close();
390  }
391 
392  private function remove(): void
393  {
394  if (!$this->view_request->canUserAdministrate()) {
395  $this->abortWithPermissionDenied();
396  return;
397  }
398  $rids = $this->getResourceIdsFromRequest();
399  if (empty($rids)) {
400  $this->main_tpl->setOnScreenMessage('failure', $this->language->txt('msg_no_perm_read'), true);
401  $this->ctrl->redirect($this, self::CMD_INDEX);
402  return;
403  }
404  foreach ($rids as $rid) {
405  if (!$this->view_request->getCollection()->isIn($rid)) {
406  $this->main_tpl->setOnScreenMessage('failure', $this->language->txt('msg_no_perm_read'), true);
407  $this->ctrl->redirect($this, self::CMD_INDEX);
408  return;
409  }
410  }
411 
412  foreach ($rids as $rid) {
413  $this->irss->manage()->remove($rid, $this->view_configuration->getStakeholder());
414  }
415 
416  $this->main_tpl->setOnScreenMessage('success', $this->language->txt('rids_deleted'), true);
417  $this->ctrl->redirect($this, self::CMD_INDEX);
418  }
419 
420  // REQUEST HELPERS
421 
425  private function getResourceIdsFromRequest(): array
426  {
427  $token = $this->action_builder->getUrlToken();
428  $wrapper = $this->http->wrapper();
429  $to_string = $this->refinery->kindlyTo()->string();
430  $to_array_of_string = $this->refinery->to()->listOf($to_string);
431  $rid_string = null;
432 
433  if ($wrapper->query()->has($token->getName())) {
434  try {
435  $rid_string = $wrapper->query()->retrieve(
436  $token->getName(),
437  $to_string
438  );
439  $rid_strings = explode(',', $rid_string);
440  } catch (ConstraintViolationException $e) {
441  $rid_strings = $wrapper->query()->retrieve(
442  $token->getName(),
443  $to_array_of_string
444  );
445  }
446  }
447 
448  if ($wrapper->post()->has('interruptive_items')) {
449  $rid_strings = $wrapper->post()->retrieve(
450  'interruptive_items',
451  $to_array_of_string
452  );
453  }
454 
455  if(empty($rid_strings)) {
456  // try single resource
457  $rid_strings = $this->http->wrapper()->query()->has(self::P_RESOURCE_ID)
458  ? [$this->http->wrapper()->query()->retrieve(self::P_RESOURCE_ID, $this->refinery->kindlyTo()->string())]
459  : [];
460  }
461 
462  if (isset($rid_strings[0]) && $rid_strings[0] === 'ALL_OBJECTS') {
463  return $this->view_request->getCollection()->getResourceIdentifications();
464  }
465 
466  if ($rid_strings === []) {
467  return [];
468  }
469  $resource_identifications = [];
470  foreach ($rid_strings as $rid_string) {
471  $resource_identification = $this->irss->manage()->find($this->unhash($rid_string));
472  if ($resource_identification === null) {
473  continue;
474  }
475  $resource_identifications[] = $resource_identification;
476  }
477  return $resource_identifications;
478  }
479 
480  // UPLOAD HANDLER
481  public function getFileIdentifierParameterName(): string
482  {
483  return self::P_RESOURCE_ID;
484  }
485 
486  public function getUploadURL(): string
487  {
488  return $this->ctrl->getLinkTarget($this, self::CMD_UPLOAD);
489  }
490 
491  public function getFileRemovalURL(): string
492  {
493  return '';
494  }
495 
496  public function getExistingFileInfoURL(): string
497  {
498  return $this->ctrl->getLinkTarget($this, self::CMD_INFO);
499  }
500 
501  public function getInfoForExistingFiles(array $file_ids): array
502  {
503  return [];
504  }
505 
506  public function getInfoResult(string $identifier): ?FileInfoResult
507  {
508  return null;
509  }
510 
511  public function supportsChunkedUploads(): bool
512  {
513  return false;
514  }
515 }
Will keep the top directory of the ZIP file if there is one (simple unzip).
$response
Definition: xapitoken.php:93
global $DIC
Definition: feed.php:28
$provider
Definition: ltitoken.php:83
ILIAS Filesystem Util Archive Archives $archive
static http()
Fetches the global http state from ILIAS.
__construct(private Configuration $view_configuration)
$token
Definition: xapitoken.php:70
ILIAS ResourceStorage Services $irss
ILIAS FileUpload FileUpload $upload
ilGlobalTemplateInterface $main_tpl