Fixed bug #16786: Generating preview link not working since Update to 4.4.5
[Packages/TYPO3.CMS.git] / typo3 / sysext / version / ws / index.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2010 Kasper Skårhøj (kasperYYYY@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Module: Workspace manager
29 *
30 * $Id: index.php 9427 2010-11-17 08:38:31Z benni $
31 *
32 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
33 * @author Dmitry Dulepov <typo3@accio.lv>
34 */
35 /**
36 * [CLASS/FUNCTION INDEX of SCRIPT]
37 *
38 *
39 *
40 * 101: class SC_mod_user_ws_index extends t3lib_SCbase
41 *
42 * SECTION: Standard module initialization
43 * 128: function menuConfig()
44 * 175: function init()
45 * 233: function main()
46 * 280: function printContent()
47 *
48 * SECTION: Module content: Publish
49 * 310: function moduleContent_publish()
50 * 411: function displayVersionDetails($details)
51 * 420: function displayWorkspaceOverview()
52 *
53 * SECTION: Module content: Workspace list
54 * 461: function moduleContent_workspaceList()
55 * 476: function workspaceList_displayUserWorkspaceList()
56 * 553: function workspaceList_getUserWorkspaceList()
57 * 592: function workspaceList_formatWorkspaceData(&$wksp)
58 * 634: function workspaceList_getWebMountPoints(&$wksp)
59 * 683: function workspaceList_getFileMountPoints(&$wksp)
60 * 736: function workspaceList_displayUserWorkspaceListHeader()
61 * 756: function workspaceList_getUserList(&$wksp)
62 * 783: function workspaceList_getUserListForSysWorkspace(&$wksp)
63 * 810: function workspaceList_getUserListWithAccess(&$list, $access)
64 * 883: function workspaceList_displayIcons($currentWorkspace, &$wksp)
65 * 931: function workspaceList_hasEditAccess(&$wksp)
66 * 943: function workspaceList_createFakeWorkspaceRecord($uid)
67 *
68 * TOTAL FUNCTIONS: 20
69 * (This index is automatically created/updated by the extension "extdeveval")
70 *
71 */
72
73 // Initialize module:
74 unset($MCONF);
75 require ('conf.php');
76 require ($BACK_PATH.'init.php');
77 require ($BACK_PATH.'template.php');
78 $BE_USER->modAccess($MCONF,1);
79
80 // Include libraries of various kinds used inside:
81 $LANG->includeLLFile('EXT:lang/locallang_mod_user_ws.xml');
82 $LANG->includeLLFile('EXT:lang/locallang_misc.xml');
83 require_once('class.wslib.php');
84 require_once('class.wslib_gui.php');
85
86
87
88
89 /**
90 * Module: Workspace manager
91 *
92 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
93 * @package TYPO3
94 * @subpackage core
95 */
96 class SC_mod_user_ws_index extends t3lib_SCbase {
97
98 // Default variables for backend modules
99 var $MCONF = array(); // Module configuration
100 var $MOD_MENU = array(); // Module menu items
101 var $MOD_SETTINGS = array(); // Module session settings
102
103 /**
104 * Document Template Object
105 *
106 * @var noDoc
107 */
108 var $doc;
109 var $content; // Accumulated content
110
111
112 // Internal:
113 var $publishAccess = FALSE;
114 var $be_user_Array = array();
115 var $be_user_Array_full = array(); // not blinded, used by workspace listing
116 protected $showDraftWorkspace = FALSE; // Determines whether the draft workspace is shown
117
118
119 /*********************************
120 *
121 * Standard module initialization
122 *
123 *********************************/
124
125 /**
126 * Initialize menu configuration
127 *
128 * @return void
129 */
130 function menuConfig() {
131 global $LANG;
132
133 // fetches the configuration of the version extension
134 $versionExtconf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['version']);
135 // show draft workspace only if enabled in the version extensions config
136 if($versionExtconf['showDraftWorkspace']) {
137 $this->showDraftWorkspace = TRUE;
138 }
139
140 // Menu items:
141 $this->MOD_MENU = array(
142 'function' => array(
143 'publish' => $LANG->getLL('menuitem_review'),
144 'workspaces' => $LANG->getLL('menuitem_workspaces'),
145 ),
146 'filter' => array(
147 1 => $LANG->getLL('filter_drafts'),
148 2 => $LANG->getLL('filter_archive'),
149 0 => $LANG->getLL('filter_all'),
150 ),
151 'display' => array(
152 0 => '['.$LANG->getLL('shortcut_onlineWS').']',
153 -98 => $LANG->getLL('label_offlineWSes'),
154 -99 => $LANG->getLL('label_allWSes')
155 ),
156 'diff' => array(
157 0 => $LANG->getLL('diff_no_diff'),
158 1 => $LANG->getLL('diff_show_inline'),
159 2 => $LANG->getLL('diff_show_popup'),
160 ),
161 'expandSubElements' => '',
162 );
163
164 // check if draft workspace was enabled, and if the user has access to it
165 if ($this->showDraftWorkspace === TRUE && $GLOBALS['BE_USER']->checkWorkspace(array('uid' => -1))) {
166 $this->MOD_MENU['display'][-1] = '[' . $LANG->getLL('shortcut_offlineWS') . ']';
167 }
168
169 // Add workspaces:
170 if ($GLOBALS['BE_USER']->workspace===0) { // Spend time on this only in online workspace because it might take time:
171 $workspaces = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,title,adminusers,members,reviewers','sys_workspace','pid=0'.t3lib_BEfunc::deleteClause('sys_workspace'),'','title');
172 foreach($workspaces as $rec) {
173 if ($GLOBALS['BE_USER']->checkWorkspace($rec)) {
174 $this->MOD_MENU['display'][$rec['uid']] = '[' . $rec['uid'] . '] ' . htmlspecialchars($rec['title']);
175 }
176 }
177 }
178
179 // CLEANSE SETTINGS
180 $this->MOD_SETTINGS = t3lib_BEfunc::getModuleData($this->MOD_MENU, t3lib_div::_GP('SET'), $this->MCONF['name'], 'ses');
181 }
182
183 /**
184 * Executes action for selected elements, if any is sent:
185 */
186 function execute() {
187 $post = t3lib_div::_POST();
188
189 # debug($post);
190
191 if ($post['_with_selected_do']) {
192 if (is_array($post['items']) && count($post['items'])) {
193 $cmdArray = array();
194
195 foreach($post['items'] as $item => $v) {
196 list($table,$uid) = explode(':',$item,2);
197
198 if ($GLOBALS['TCA'][$table] && t3lib_div::testInt($uid)) {
199 switch($post['_with_selected_do']) {
200 case "stage_-1":
201 $cmdArray[$table][$uid]['version']['action'] = 'setStage';
202 $cmdArray[$table][$uid]['version']['stageId'] = -1;
203 break;
204 case "stage_0":
205 $cmdArray[$table][$uid]['version']['action'] = 'setStage';
206 $cmdArray[$table][$uid]['version']['stageId'] = 0;
207 break;
208 case "stage_1":
209 $cmdArray[$table][$uid]['version']['action'] = 'setStage';
210 $cmdArray[$table][$uid]['version']['stageId'] = 1;
211 break;
212 case "stage_10":
213 $cmdArray[$table][$uid]['version']['action'] = 'setStage';
214 $cmdArray[$table][$uid]['version']['stageId'] = 10;
215 break;
216 case "publish":
217 if ($onlineRec = t3lib_BEfunc::getLiveVersionOfRecord($table,$uid,'uid')) {
218 $cmdArray[$table][$onlineRec['uid']]['version']['action'] = 'swap';
219 $cmdArray[$table][$onlineRec['uid']]['version']['swapWith'] = $uid;
220 }
221 break;
222 case "swap":
223 if ($onlineRec = t3lib_BEfunc::getLiveVersionOfRecord($table,$uid,'uid')) {
224 $cmdArray[$table][$onlineRec['uid']]['version']['action'] = 'swap';
225 $cmdArray[$table][$onlineRec['uid']]['version']['swapWith'] = $uid;
226 $cmdArray[$table][$onlineRec['uid']]['version']['swapIntoWS'] = 1;
227 }
228 break;
229 case "release":
230 $cmdArray[$table][$uid]['version']['action'] = 'clearWSID';
231 break;
232 case "flush":
233 $cmdArray[$table][$uid]['version']['action'] = 'flush';
234 break;
235 }
236 }
237 }
238
239 /** @var $tce t3lib_TCEmain */
240 $tce = t3lib_div::makeInstance('t3lib_TCEmain');
241 $tce->stripslashes_values = 0;
242 $tce->start(array(), $cmdArray);
243 $tce->process_cmdmap();
244 $tce->printLogErrorMessages('');
245 }
246 }
247 }
248
249 /**
250 * Standard init function of a module.
251 *
252 * @return void
253 */
254 function init() {
255 global $BACK_PATH, $BE_USER;
256
257 // Setting module configuration:
258 $this->MCONF = $GLOBALS['MCONF'];
259
260 // Initialize Document Template object:
261 $this->doc = t3lib_div::makeInstance('template');
262 $this->doc->backPath = $BACK_PATH;
263 $this->doc->setModuleTemplate('templates/ws.html');
264
265 // JavaScript
266 $this->doc->JScode = $this->doc->wrapScriptTags('
267 script_ended = 0;
268 function jumpToUrl(URL) { //
269 window.location.href = URL;
270 }
271
272 function expandCollapse(rowNumber) {
273 elementId = "wl_" + rowNumber;
274 element = document.getElementById(elementId);
275 image = document.getElementById("spanw1_" + rowNumber);
276 if (element.style) {
277 if (element.style.display == "none") {
278 element.style.display = "table-row";
279 image.className = "t3-icon t3-icon-actions t3-icon-actions-view t3-icon-view-table-collapse";
280 } else {
281 element.style.display = "none";
282 image.className = "t3-icon t3-icon-actions t3-icon-actions-view t3-icon-view-table-expand";
283 }
284 }
285 }
286 ');
287 $this->doc->form = '<form action="index.php" method="post" name="pageform">';
288
289 // Setting up the context sensitive menu:
290 $this->doc->getContextMenuCode();
291
292 // Setting publish access permission for workspace:
293 $this->publishAccess = $BE_USER->workspacePublishAccess($BE_USER->workspace);
294
295 // Parent initialization:
296 parent::init();
297 }
298
299 /**
300 * Main function for Workspace Manager module.
301 *
302 * @return void
303 */
304 function main() {
305 global $LANG, $BE_USER, $BACK_PATH;
306
307 // See if we need to switch workspace
308 $changeWorkspace = t3lib_div::_GET('changeWorkspace');
309 if ($changeWorkspace != '') {
310 $BE_USER->setWorkspace($changeWorkspace);
311 $this->content .= $this->doc->wrapScriptTags('top.location.href="' . $BACK_PATH . t3lib_BEfunc::getBackendScript() . '";');
312 } else {
313 // Starting page:
314 $this->content.=$this->doc->header($LANG->getLL('title'));
315 $this->content.=$this->doc->spacer(5);
316
317 // Get usernames and groupnames
318 $be_group_Array = t3lib_BEfunc::getListGroupNames('title,uid');
319 $groupArray = array_keys($be_group_Array);
320 // Need 'admin' field for t3lib_iconWorks::getIconImage()
321 $this->be_user_Array_full = $this->be_user_Array = t3lib_BEfunc::getUserNames('username,usergroup,usergroup_cached_list,uid,admin,workspace_perms');
322 if (!$GLOBALS['BE_USER']->isAdmin()) {
323 $this->be_user_Array = t3lib_BEfunc::blindUserNames($this->be_user_Array,$groupArray,1);
324 }
325
326 // Build top menu:
327 $menuItems = array();
328 $menuItems[] = array(
329 'label' => $LANG->getLL('menuitem_review'),
330 'content' => $this->moduleContent_publish()
331 );
332 $menuItems[] = array(
333 'label' => $LANG->getLL('menuitem_workspaces'),
334 'content' => $this->moduleContent_workspaceList()
335 );
336
337 // Add hidden fields and create tabs:
338 $content = $this->doc->getDynTabMenu($menuItems, 'user_ws');
339 $this->content.=$this->doc->section('',$content,0,1);
340
341 // Setting up the buttons and markers for docheader
342 $docHeaderButtons = $this->getButtons();
343 // $markers['CSH'] = $docHeaderButtons['csh'];
344
345 }
346 $markers['CONTENT'] = $this->content;
347
348 // Build the <body> for the module
349 $this->content = $this->doc->startPage($LANG->getLL('title'));
350 $this->content.= $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $markers);
351 $this->content.= $this->doc->endPage();
352 $this->content = $this->doc->insertStylesAndJS($this->content);
353
354 }
355
356 /**
357 * Print module content. Called as last thing in the global scope.
358 *
359 * @return void
360 */
361 function printContent() {
362 echo $this->content;
363 }
364
365 /**
366 * Create the panel of buttons for submitting the form or otherwise perform operations.
367 *
368 * @return array all available buttons as an assoc. array
369 */
370 protected function getButtons() {
371 global $LANG, $BACK_PATH;
372
373 $buttons = array(
374 'new_record' => '',
375 );
376
377 $newWkspUrl = 'workspaceforms.php?action=new';
378
379 // workspace creation link
380 if ($GLOBALS['BE_USER']->isAdmin() || 0 != ($GLOBALS['BE_USER']->groupData['workspace_perms'] & 4)) {
381 $buttons['new_record'] = '<a href="' . $newWkspUrl . '">' .
382 '<img ' . t3lib_iconWorks::skinImg($BACK_PATH, 'gfx/add_workspaces.gif') . ' alt="' . $LANG->getLL('img_title_create_new_workspace') . '" id="ver-wl-new-workspace-icon" />' .
383 '</a>';
384 }
385 return $buttons;
386 }
387
388
389
390
391
392
393
394
395
396
397
398 /*********************************
399 *
400 * Module content: Publish
401 *
402 *********************************/
403
404 /**
405 * Rendering the content for the publish and review panel in the workspace manager
406 *
407 * @return string HTML content
408 */
409 function moduleContent_publish() {
410 global $LANG;
411
412 // Initialize:
413 $content = '';
414 $details = t3lib_div::_GP('details');
415
416 // Create additional menus:
417 $menu = '';
418 if ($GLOBALS['BE_USER']->workspace===0) {
419 $menu.= t3lib_BEfunc::getFuncMenu(0,'SET[filter]',$this->MOD_SETTINGS['filter'],$this->MOD_MENU['filter']);
420 $menu.= t3lib_BEfunc::getFuncMenu(0,'SET[display]',$this->MOD_SETTINGS['display'],$this->MOD_MENU['display']);
421 }
422 $menu.= t3lib_BEfunc::getFuncMenu(0,'SET[diff]',$this->MOD_SETTINGS['diff'],$this->MOD_MENU['diff']);
423 if ($GLOBALS['BE_USER']->workspace!==0) {
424 $menu.= t3lib_BEfunc::getFuncCheck(0,'SET[expandSubElements]',$this->MOD_SETTINGS['expandSubElements'],'','','id="checkExpandSubElements"').' <label for="checkExpandSubElements">'.$LANG->getLL('label_showsubelements').'</label> ';
425 }
426
427 // Create header:
428 $title = '';
429 $description = '';
430 switch($GLOBALS['BE_USER']->workspace) {
431 case 0:
432 $title = t3lib_iconWorks::getIconImage('sys_workspace', array(), $this->doc->backPath, ' align="top"').'['.$LANG->getLL('shortcut_onlineWS').']';
433 $description = $LANG->getLL('workspace_description_live');
434 break;
435 case -1:
436 $title = t3lib_iconWorks::getIconImage('sys_workspace', array(), $this->doc->backPath, ' align="top"').'['.$LANG->getLL('shortcut_offlineWS').']';
437 $description = $LANG->getLL('workspace_description_draft');
438 break;
439 case -99:
440 $title = $this->doc->icons(3).'[' . $LANG->getLL('shortcut_noWSfound') . ']';
441 $description = $LANG->getLL('workspace_description_no_access');
442 break;
443 default:
444 $title = t3lib_iconWorks::getIconImage('sys_workspace', $GLOBALS['BE_USER']->workspaceRec, $this->doc->backPath, ' align="top"').
445 '['.$GLOBALS['BE_USER']->workspace.'] '.t3lib_BEfunc::getRecordTitle('sys_workspace',$GLOBALS['BE_USER']->workspaceRec,TRUE);
446 $description = $GLOBALS['BE_USER']->workspaceRec['description'];
447 break;
448 }
449
450 // Buttons for publish / swap:
451 $actionLinks = '';
452 if ($GLOBALS['BE_USER']->workspace!==0) {
453 if ($this->publishAccess) {
454 $confirmation = $LANG->JScharCode($LANG->getLL(($GLOBALS['BE_USER']->workspaceRec['publish_access'] & 1) ? 'submit_publish_workspace_confirmation_1' : 'submit_publish_workspace_confirmation_2'));
455 $actionLinks.= '<input type="submit" name="_publish" value="' . $LANG->getLL('submit_publish_workspace') . '" onclick="if (confirm(' . $confirmation . ')) window.location.href=\'publish.php?swap=0\';return false"/>';
456 if ($GLOBALS['BE_USER']->workspaceSwapAccess()) {
457 $confirmation = $LANG->JScharCode($LANG->getLL(($GLOBALS['BE_USER']->workspaceRec['publish_access'] & 1) ? 'submit_swap_workspace_confirmation_1' : 'submit_swap_workspace_confirmation_2'));
458 $actionLinks.= '<input type="submit" name="_swap" value="' . $LANG->getLL('submit_swap_workspace') . '" onclick="if (confirm(' . $confirmation . ')) window.location.href=\'publish.php?swap=1\';return false ;" />';
459 }
460 } else {
461 $actionLinks.= $this->doc->icons(1) . $LANG->getLL('no_publish_permission');
462 }
463
464 // Preview of workspace link
465 if (t3lib_div::_POST('_previewLink')) {
466 $ttlHours = intval($GLOBALS['BE_USER']->getTSConfigVal('options.workspaces.previewLinkTTLHours'));
467 $ttlHours = ($ttlHours ? $ttlHours : 24*2);
468 $previewUrl = t3lib_BEfunc::getViewDomain($this->id) . '/index.php?ADMCMD_prev=' . t3lib_BEfunc::compilePreviewKeyword('', $GLOBALS['BE_USER']->user['uid'], 60*60*$ttlHours, $GLOBALS['BE_USER']->workspace) . '&id=' . intval($GLOBALS['BE_USER']->workspaceRec['db_mountpoints']);
469 $actionLinks.= '<br />Any user can browse the workspace frontend using this link for the next ' . $ttlHours . ' hours (does not require backend login):<br /><br /><a target="_blank" href="' . htmlspecialchars($previewUrl) . '">' . $previewUrl . '</a>';
470 } else {
471 $actionLinks.= '<input type="submit" name="_previewLink" value="Generate Workspace Preview Link" />';
472 }
473 }
474
475 $wsAccess = $GLOBALS['BE_USER']->checkWorkspace($GLOBALS['BE_USER']->workspaceRec);
476
477 // Add header to content variable:
478 $content = '
479 <table border="0" cellpadding="0" cellspacing="0" id="t3-user-ws-wsinfotable" class="t3-table t3-table-info">
480 <tr>
481 <td class="t3-col-header" nowrap="nowrap">' . $LANG->getLL('label_workspace') . '&nbsp;</th>
482 <td nowrap="nowrap">' . $title . '</td>
483 </tr>
484 <tr>' . ($description ? '
485 <td class="t3-col-header" nowrap="nowrap">' . $LANG->getLL('label_description') . '&nbsp;</td>
486 <td>' . $description . '</td>
487 </tr>' : '') . ($GLOBALS['BE_USER']->workspace!=-99 && !$details ? '
488 <tr>
489 <td class="t3-col-header" nowrap="nowrap">' . $LANG->getLL('label_options') . '&nbsp;</td>
490 <td>' . $menu . $actionLinks . '</td>
491 </tr>
492 <tr>
493 <td class="t3-col-header" nowrap="nowrap">' . $LANG->getLL('label_status') . '&nbsp;</td>
494 <td>' . $LANG->getLL('label_access_level') . ' ' . $GLOBALS['LANG']->getLL('workspace_list_access_' . $wsAccess['_ACCESS']) . '</td>
495 </tr>' : '').'
496 </table>
497 <br />
498 ';
499
500 // Add publishing and review overview:
501 if ($GLOBALS['BE_USER']->workspace!=-99) {
502 if ($details) {
503 $content.= $this->displayVersionDetails($details);
504 } else {
505 $content.= $this->displayWorkspaceOverview();
506 }
507 $content .= '<br />';
508 }
509
510 // Return content:
511 return $content;
512 }
513
514 /**
515 * Display details for a single version from workspace
516 *
517 * @param string Version identification, made of table and uid
518 * @return string HTML string
519 */
520 function displayVersionDetails($details) {
521 return 'TODO: Show details for version "'.$details.'"<hr/><a href="index.php">BACK</a>';
522 }
523
524 /**
525 * Rendering the overview of versions in the current workspace
526 *
527 * @return string HTML (table)
528 */
529 function displayWorkspaceOverview() {
530
531 // Initialize Workspace ID and filter-value:
532 if ($GLOBALS['BE_USER']->workspace===0) {
533 $wsid = $this->MOD_SETTINGS['display']; // Set wsid to the value from the menu (displaying content of other workspaces)
534 $filter = $this->MOD_SETTINGS['filter'];
535 } else {
536 $wsid = $GLOBALS['BE_USER']->workspace;
537 $filter = 0;
538 }
539
540 // Instantiate workspace GUI library and generate workspace overview
541 $wslibGuiObj = t3lib_div::makeInstance('wslib_gui');
542 $wslibGuiObj->diff = $this->MOD_SETTINGS['diff'];
543 $wslibGuiObj->expandSubElements = $this->MOD_SETTINGS['expandSubElements'];
544 $wslibGuiObj->alwaysDisplayHeader = true;
545 return $wslibGuiObj->getWorkspaceOverview($this->doc, $wsid, $filter);
546 }
547
548
549
550
551
552
553
554
555
556
557
558
559
560 /********************************
561 *
562 * Module content: Workspace list
563 *
564 ********************************/
565
566 /**
567 * Rendering of the workspace list
568 *
569 * @return string HTML
570 */
571 function moduleContent_workspaceList() {
572 // Original Kasper's TODO: Workspace listing
573 //
574 // - LISTING: Shows list of available workspaces for user. Used can see title, description, publication time, freeze-state, db-mount, member users/groups etc. Current workspace is indicated.
575 // - SWITCHING: Switching between available workspaces is done by a button shown for each in the list
576 // - ADMIN: Administrator of a workspace can click an edit-button linking to a form where he can edit the workspace. Users and groups should be selected based on some filtering so he cannot select groups he is not a member off himself (or some other rule... like for permission display with blinded users/groups)
577 // - CREATE: If allowed, the user can create a new workspace which brings up a form where he can enter basic data. This is saved by a local instance of tcemain with forced admin-rights (creation in pid=0!).
578 return $this->workspaceList_displayUserWorkspaceList();
579 }
580
581 /**
582 * Generates HTML to display a list of workspaces.
583 *
584 * @return string Generated HTML code
585 */
586 function workspaceList_displayUserWorkspaceList() {
587 global $BACK_PATH, $LANG;
588
589 // table header
590 $content = $this->workspaceList_displayUserWorkspaceListHeader();
591
592 // get & walk workspace list generating content
593 $wkspList = $this->workspaceList_getUserWorkspaceList();
594 $rowNum = 1;
595 foreach ($wkspList as $wksp) {
596 $currentWksp = ($GLOBALS['BE_USER']->workspace == $wksp['uid']);
597
598 // Each workspace data occupies two rows:
599 // (1) Folding + Icons + Title + Description
600 // (2) Information about workspace (initially hidden)
601
602 $cssClass = ($currentWksp ? 't3-row t3-row-active bgColor3' : 't3-row bgColor4');
603 // Start first row
604 $content .= '<tr class="' . $cssClass . '">';
605
606 // row #1, column #1: expand icon
607 $content .= '<td>' .
608 '<a href="javascript:expandCollapse(' . $rowNum . ')">' .
609 t3lib_iconWorks::getSpriteIcon('actions-view-table-expand', array(
610 'title' => $LANG->getLL('img_title_show_more'),
611 'id' => 'spanw1_' . $rowNum
612 )) .
613 '</a></td>';
614
615 // row #1, column #2: icon panel
616 $content .= '<td nowrap="nowrap">'; // Mozilla Firefox will attempt wrap due to `width="1"` on topmost column
617 $content .= $this->workspaceList_displayIcons($currentWksp, $wksp);
618 $content .= '</td>';
619
620 // row #1, column #3: current workspace indicator
621 $content .= '<td nowrap="nowrap" style="text-align: center">'; // Mozilla Firefox will attempt wrap due to `width="1"` on topmost column
622 $content .= (!$currentWksp ? '&nbsp;' : '<img ' . t3lib_iconWorks::skinImg($BACK_PATH, 'gfx/icon_ok.gif', 'width="18" height="16"') . ' id="wl_' . $rowNum . 'i" border="0" hspace="1" alt="' . $LANG->getLL('img_title_current_workspace') . '" />');
623 $content .= '</td>';
624
625 // row #1, column #4 and 5: title and description
626 $content .= '<td nowrap="nowrap">' . htmlspecialchars($wksp['title']) . '</td>' .
627 '<td>' . nl2br(htmlspecialchars($wksp['description'])) . '</td>';
628 $content .= '</tr>';
629
630 // row #2, column #1 and #2
631 $content .= '<tr id="wl_' . $rowNum . '" class="bgColor" style="display: none">';
632 $content .= '<td colspan="2" style="border-right: none;">&nbsp;</td>';
633
634 // row #2, column #3, #4 and #4
635 $content .= '<td colspan="3" style="border-left: none;">' .
636 $this->workspaceList_formatWorkspaceData($wksp) .
637 '</td>';
638
639 $content .= '</tr>';
640 $rowNum++;
641 }
642 $content .= '</table>';
643
644 return $content;
645 }
646
647
648
649
650
651 /**
652 * Retrieves a list of workspaces where user has access.
653 *
654 * @return array A list of workspaces available to the current BE user
655 */
656 function workspaceList_getUserWorkspaceList() {
657
658 // Get list of all workspaces. Note: system workspaces will be always displayed before custom ones!
659 $workspaces = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*','sys_workspace','pid=0'.t3lib_BEfunc::deleteClause('sys_workspace'),'','title');
660 $availableWorkspaces = array();
661
662 // Live
663 $wksp = $this->workspaceList_createFakeWorkspaceRecord(0);
664 $wksp = $GLOBALS['BE_USER']->checkWorkspace($wksp);
665 if (false !== $wksp) {
666 $availableWorkspaces[] = $wksp;
667 }
668
669 // Draft
670 $wksp = $this->workspaceList_createFakeWorkspaceRecord(-1);
671 $wksp = $GLOBALS['BE_USER']->checkWorkspace($wksp);
672 if (false !== $wksp) {
673 $availableWorkspaces[] = $wksp;
674 }
675
676 // Custom
677 foreach($workspaces as $rec) {
678 // see if user can access this workspace in any way
679 if (false !== ($result = $GLOBALS['BE_USER']->checkWorkspace($rec))) {
680 $availableWorkspaces[] = $result; // `$result` contains `$rec` plus access type through '_ACCESS' key
681 }
682 }
683 return $availableWorkspaces;
684 }
685
686 /**
687 * Create inner information panel for workspace list. This panel is
688 * initially hidden and becomes visible when user click on the expand
689 * icon on the very left of workspace list against the workspace he
690 * wants to explore.
691 *
692 * @param array Workspace information
693 * @return string Formatted workspace information
694 */
695 function workspaceList_formatWorkspaceData(&$wksp) {
696 global $LANG;
697
698 $content = '<table cellspacing="0" cellpadding="0" width="100%" class="ver-wl-details-table">' .
699 '<tr><td class="ver-wl-details-label"><strong>' . $LANG->getLL('workspace_list_label_file_mountpoints') . '</strong></td>' .
700 '<td class="ver-wl-details">' . $this->workspaceList_getFileMountPoints($wksp) . '</td></tr>' .
701 '<tr><td class="ver-wl-details-label"><strong>' . $LANG->getLL('workspace_list_label_db_mountpoints') . '</strong></td>' .
702 '<td class="ver-wl-details">' . $this->workspaceList_getWebMountPoints($wksp) . '</td></tr>';
703 if ($wksp['uid'] > 0) {
704 // Displaying information below makes sence only for custom workspaces
705 $content .=
706 '<tr><td class="ver-wl-details-label"><strong>' . $LANG->getLL('workspace_list_label_frozen') . '</strong></td>' .
707 '<td class="ver-wl-details">' . $LANG->getLL($wksp['freeze'] ? 'workspace_list_label_frozen_yes' : 'workspace_list_label_frozen_no') . '</td></tr>' .
708 '<tr><td class="ver-wl-details-label"><strong>' . $LANG->getLL('workspace_list_label_publish_date') . '</strong></td>' .
709 '<td class="ver-wl-details">' . ($wksp['publish_time'] == 0 ? '&nbsp;&ndash;' : t3lib_BEfunc::datetime($wksp['publish_time'])) . '</td></tr>' .
710 '<tr><td class="ver-wl-details-label"><strong>' . $LANG->getLL('workspace_list_label_unpublish_date') . '</strong></td>' .
711 '<td class="ver-wl-details">' . ($wksp['unpublish_time'] == 0 ? '&nbsp;&ndash;' : t3lib_BEfunc::datetime($wksp['unpublish_time'])) . '</td></tr>' .
712 '<tr><td class="ver-wl-details-label"><strong>' . $LANG->getLL('workspace_list_label_your_access') . '</strong></td>' .
713 '<td class="ver-wl-details">' . $LANG->getLL('workspace_list_access_' . $wksp['_ACCESS']) . '</td></tr>' .
714 '<tr><td class="ver-wl-details-label"><strong>' . $LANG->getLL('workspace_list_label_workspace_users') . '</strong></td>' .
715 '<td class="ver-wl-details">' . $this->workspaceList_getUserList($wksp) . '</td></tr>';
716 }
717 else if ($GLOBALS['BE_USER']->isAdmin()) {
718 // show users for draft/live workspace only to admin users
719 $content .= '<tr><td class="ver-wl-details-label"><strong>' . $LANG->getLL('workspace_list_label_workspace_users') . '</strong></td>' .
720 '<td class="ver-wl-details">' . $this->workspaceList_getUserList($wksp) . '</td></tr>';
721 }
722 $content .= '</table>';
723
724 return $content;
725 }
726
727
728
729
730
731 /**
732 * Retrieves and formats database mount points lists.
733 *
734 * @param array &$wksp Workspace record
735 * @return string Generated HTML
736 */
737 function workspaceList_getWebMountPoints(&$wksp) {
738 if ($wksp['uid'] == -1) {
739 // draft workspace
740 return $GLOBALS['LANG']->getLL('workspace_list_db_mount_point_draft');
741 } else if ($wksp['uid'] == 0) {
742 // live workspace
743 return $GLOBALS['LANG']->getLL('workspace_list_db_mount_point_live');
744 }
745 // -- here only if obtaining mount points for custom workspaces
746
747 // We need to fetch user's mount point list (including MPS mounted from groups).
748 // This list must not be affects by current user's workspace. It means we cannot use
749 // $BE_USER->isInWebMount() to check mount points.
750 $mountpointList = $GLOBALS['BE_USER']->groupData['webmounts'];
751 // If there are DB mountpoints in the workspace record,
752 // then only show the ones that are allowed there (and that are in the users' webmounts)
753 if (trim($wksp['db_mountpoints'])) {
754 $userMountpoints = explode(',', $mountpointList);
755 // now filter the users' to only keep the mountpoints
756 // that are also in the workspaces' db_mountpoints
757 $workspaceMountpoints = explode(',', $wksp['db_mountpoints']);
758 $filteredMountpoints = array_intersect($userMountpoints, $workspaceMountpoints);
759 $mountpointList = implode(',', $filteredMountpoints);
760 }
761
762 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
763 '*', // All fields needed for t3lib_iconWorks::getSpriteIconForRecord()
764 'pages',
765 'deleted = 0 AND uid IN (' . $GLOBALS['TYPO3_DB']->cleanIntList($mountpointList) . ')',
766 '',
767 'title'
768 );
769
770 $content = array();
771 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
772 // will show UID on hover. Just convinient to user.
773 $content[] = t3lib_iconWorks::getSpriteIconForRecord('pages', $row) . '<span title="UID: ' . $row['uid'] . '">' . $row['title'] . '</span>';
774 }
775
776 if (count($content)) {
777 return implode('<br />', $content);
778 } else {
779 // no mount points
780 return $GLOBALS['LANG']->getLL('workspace_list_db_mount_point_custom');
781 }
782 }
783
784
785 /**
786 * Retrieves and formats file mount points lists.
787 *
788 * @param array &$wksp Workspace record
789 * @return string Generated HTML
790 */
791 function workspaceList_getFileMountPoints(&$wksp) {
792 if ($wksp['uid'] == -1) {
793 // draft workspace - none!
794 return $GLOBALS['LANG']->getLL('workspace_list_file_mount_point_draft');
795 } else if ($wksp['uid'] == 0) {
796 // live workspace
797 return $GLOBALS['LANG']->getLL('workspace_list_file_mount_point_live');
798 }
799 // -- here only if displaying information for custom workspace
800
801 // We need to fetch user's mount point list (including MPS mounted from groups).
802 // This list must not be affects by current user's workspace. It means we cannot use
803 // $BE_USER->isInWebMount() to check mount points.
804 $mountpointList = implode(',', $GLOBALS['BE_USER']->groupData['filemounts']);
805 // If there are file mountpoints in the workspace record,
806 // then only show the ones that are allowed there (and that are in the users' file mounts)
807 if (trim($wksp['file_mountpoints'])) {
808 $userMountpoints = explode(',', $mountpointList);
809 // now filter the users' to only keep the mountpoints
810 // that are also in the workspaces' file_mountpoints
811 $workspaceMountpoints = explode(',', $wksp['file_mountpoints']);
812 $filteredMountpoints = array_intersect($userMountpoints, $workspaceMountpoints);
813 $mountpointList = implode(',', $filteredMountpoints);
814 }
815
816 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
817 '*', // All fields needed for t3lib_iconWorks::getSpriteIconForRecord()
818 'sys_filemounts',
819 'deleted = 0 AND hidden=0 AND uid IN (' . $GLOBALS['TYPO3_DB']->cleanIntList($mountpointList) . ')',
820 '',
821 'title'
822 );
823
824 $content = array();
825 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
826 // will show UID on hover. Just convinient to user.
827 $content[] = t3lib_iconWorks::getSpriteIconForRecord('sys_filemounts', $row) . '<span title="UID: ' . $row['uid'] . '">' . $row['title'] . '</span>';
828 }
829
830 if (count($content)) {
831 return implode('<br />', $content);
832 } else {
833 // no mount points
834 return $GLOBALS['LANG']->getLL('workspace_list_file_mount_point_custom');
835 }
836 }
837
838 /**
839 * Creates a header for the workspace list table. This function only makes
840 * <code>workspaceList_displayUserWorkspaceList()</code> smaller.
841 *
842 * @return string Generated content
843 */
844 function workspaceList_displayUserWorkspaceListHeader() {
845 global $LANG;
846 // TODO CSH lables?
847 return '<table border="0" cellpadding="0" cellspacing="0" class="workspace-overview">
848 <tr class="t3-row-header">
849 <td width="1">&nbsp;</td>
850 <td width="1">&nbsp;</td>
851 <td nowrap="nowrap">' . $LANG->getLL('workspace_list_label_current_workspace') . '</td>
852 <td nowrap="nowrap">' . $LANG->getLL('workspace_list_label_workspace_title') . '</td>
853 <td nowrap="nowrap">' . $LANG->getLL('workspace_list_label_workspace_description') . '</td>
854 </tr>';
855 }
856
857
858 /**
859 * Generates a list of <code>&lt;option&gt;</code> tags with user names.
860 *
861 * @param array Workspace record
862 * @return string Generated content
863 */
864 function workspaceList_getUserList(&$wksp) {
865 global $LANG;
866
867 if ($wksp['uid'] > 0) {
868 // custom workspaces
869 $content = $this->workspaceList_getUserListWithAccess($wksp['adminusers'], $LANG->getLL('workspace_list_label_owners')); // owners
870 $content .= $this->workspaceList_getUserListWithAccess($wksp['members'], $LANG->getLL('workspace_list_label_members')); // members
871 $content .= $this->workspaceList_getUserListWithAccess($wksp['reviewers'], $LANG->getLL('workspace_list_label_reviewers')); // reviewers
872 if ($content != '') {
873 $content = '<table cellpadding="0" cellspacing="1" width="100%" class="lrPadding workspace-overview">' . $content . '</table>';
874 } else {
875 $content = $LANG->getLL($wksp['uid'] > 0 ? 'workspace_list_access_admins_only' : 'workspace_list_access_anyone');
876 }
877 }
878 else {
879 // live and draft workspace
880 $content = $this->workspaceList_getUserListForSysWorkspace($wksp);
881 }
882 return $content;
883 }
884
885 /**
886 * Generates a list of user names that has access to the system workspace.
887 *
888 * @param array &$wksp Workspace record
889 * @return string Generated content
890 */
891 function workspaceList_getUserListForSysWorkspace(&$wksp) {
892 $option = ($wksp['uid'] == 0 ? 1 : 2);
893 $content_array = array();
894 foreach ($this->be_user_Array_full as $uid => $user) {
895 if ($user['admin'] != 0 || 0 != ($user['workspace_perms'] & $option)) {
896 if ($uid == $GLOBALS['BE_USER']->user['uid']) {
897 // highlight current user
898 $tag0 = '<span class="ver-wl-current-user">';
899 $tag1 = '</span>';
900 }
901 else {
902 $tag0 = $tag1 = '';
903 }
904 $content_array[] = $this->doc->wrapClickMenuOnIcon(t3lib_iconWorks::getIconImage('be_users', $uid, $GLOBALS['BACK_PATH'], ' align="middle" alt="UID: ' . $uid . '"'), 'be_users', $uid, 2).
905 $tag0 . htmlspecialchars($user['username']) . $tag1;
906 }
907 }
908 return implode('<br />', $content_array);
909 }
910
911 /**
912 * Generates a list of user names that has access to the workspace.
913 *
914 * @param array A list of user IDs separated by comma
915 * @param string Access string
916 * @return string Generated content
917 */
918 function workspaceList_getUserListWithAccess(&$list, $access) {
919 $content_array = array();
920 if ($list != '') {
921 $userIDs = explode(',', $list);
922
923 // get user names and sort
924 $regExp = '/^(be_[^_]+)_(\d+)$/';
925 $groups = false;
926 foreach ($userIDs as $userUID) {
927 $id = $userUID;
928
929 if (preg_match($regExp, $userUID)) {
930 $table = preg_replace($regExp, '\1', $userUID);
931 $id = intval(preg_replace($regExp, '\2', $userUID));
932 if ($table == 'be_users') {
933 // user
934 $icon = $GLOBALS['TCA']['be_users']['typeicons'][$this->be_user_Array[$id]['admin']];
935 if ($id == $GLOBALS['BE_USER']->user['uid']) {
936 // highlight current user
937 $tag0 = '<span class="ver-wl-current-user">';
938 $tag1 = '</span>';
939 }
940 else {
941 $tag0 = $tag1 = '';
942 }
943 $content_array[] = $this->doc->wrapClickMenuOnIcon(t3lib_iconWorks::getIconImage($table, $this->be_user_Array[$id], $GLOBALS['BACK_PATH'], ' align="middle" alt="UID: ' . $id . '"'), $table, $id, 2) .
944 $tag0 . htmlspecialchars($this->be_user_Array_full[$id]['username']) . $tag1;
945 }
946 else {
947 // group
948 if (false === $groups) {
949 $groups = t3lib_BEfunc::getGroupNames();
950 }
951 $content_array[] = $this->doc->wrapClickMenuOnIcon(t3lib_iconWorks::getIconImage($table, $groups[$id], $GLOBALS['BACK_PATH'], ' align="middle" alt="UID: ' . $id . '"'), $table, $id, 2) .
952 $groups[$id]['title'];
953 }
954 }
955 else {
956 // user id
957 if ($userUID == $GLOBALS['BE_USER']->user['uid']) {
958 // highlight current user
959 $tag0 = '<span class="ver-wl-current-user">';
960 $tag1 = '</span>';
961 }
962 else {
963 $tag0 = $tag1 = '';
964 }
965 $content_array[] = t3lib_iconWorks::getIconImage('be_users', $this->be_user_Array[$id], $GLOBALS['BACK_PATH'], ' align="middle" alt="UID: ' . $id . '"') .
966 $tag0 . htmlspecialchars($this->be_user_Array_full[$userUID]['username']) . $tag1;
967 }
968 }
969 sort($content_array);
970 }
971 else {
972 $content_array[] = '&nbsp;&ndash;';
973 }
974
975 $content = '<tr><td class="ver-wl-details-label ver-wl-details-user-list-label">';
976 // TODO CSH lable explaining access here?
977 $content .= '<strong>' . $access . '</strong></td>';
978 $content .= '<td class="ver-wl-details">' . implode('<br />', $content_array) . '</td></tr>';
979 return $content;
980 }
981
982
983
984 /**
985 * Creates a list of icons for workspace.
986 *
987 * @param boolean <code>true</code> if current workspace
988 * @param array Workspace record
989 * @return string Generated content
990 */
991 function workspaceList_displayIcons($currentWorkspace, &$wksp) {
992 global $BACK_PATH, $LANG;
993
994 $content = '';
995 // `edit workspace` button
996 if ($this->workspaceList_hasEditAccess($wksp)) {
997 // User can modify workspace parameters, display corresponding link and icon
998 $editUrl = 'workspaceforms.php?action=edit&amp;wkspId=' . $wksp['uid'];
999
1000 $content .= '<a href="' . $editUrl . '" title="'. $LANG->getLL('workspace_list_icon_title_edit_workspace') .'"/>' .
1001 t3lib_iconWorks::getSpriteIcon('actions-document-open') .
1002 '</a>';
1003 } else {
1004 // User can NOT modify workspace parameters, display space
1005 // Get only withdth and height from skinning API
1006 $content .= '<img src="clear.gif" ' .
1007 t3lib_iconWorks::skinImg($BACK_PATH, 'gfx/edit2.gif', 'width="11" height="12"', 2) .
1008 ' border="0" alt="" hspace="1" align="middle" />';
1009 }
1010 // `switch workspace` button
1011 if (!$currentWorkspace) {
1012 // Workspace switching button
1013 $content .= '<a href="' .
1014 t3lib_div::getIndpEnv('SCRIPT_NAME') .
1015 '?changeWorkspace=' . $wksp['uid'] . '" title="'. $LANG->getLL('workspace_list_icon_title_switch_workspace') . '"/>' .
1016 t3lib_iconWorks::getSpriteIcon('actions-version-swap-workspace') .
1017 '</a>';
1018 } else {
1019 // Current workspace: empty space instead of workspace switching button
1020 //
1021 // Here get only width and height from skinning API
1022 $content .= '<img src="clear.gif" ' .
1023 t3lib_iconWorks::skinImg($BACK_PATH, 'gfx/switch.png', 'width="18" height="16"', 2) .
1024 ' border="0" alt="" hspace="1" align="middle" alt="" />';
1025 }
1026 return $content;
1027 }
1028
1029 /**
1030 * Checks if user has edit access to workspace. Access is granted if
1031 * workspace is custom and user is admin or the the owner of the workspace.
1032 * This function assumes that <code>$wksp</code> were passed through
1033 * <code>$GLOBALS['BE_USER']->checkWorkspace()</code> function to obtain
1034 * <code>_ACCESS</code> attribute of the workspace.
1035 *
1036 * @param array Workspace record
1037 * @return boolean <code>true</code> if user can modify workspace parameters
1038 */
1039 function workspaceList_hasEditAccess(&$wksp) {
1040 $access = &$wksp['_ACCESS'];
1041 return ($wksp['uid'] > 0 && ($access == 'admin' || $access == 'owner'));
1042 }
1043
1044 /**
1045 * Creates a fake workspace record for system workspaces. Record contains
1046 * all fields found in <code>sys_workspaces</code>.
1047 *
1048 * @param integer System workspace ID. Currently <code>0</code> and <code>-1</code> are accepted.
1049 * @return array Generated record (see <code>sys_workspaces</code> for structure)
1050 */
1051 function workspaceList_createFakeWorkspaceRecord($uid) {
1052 global $BE_USER, $LANG;
1053
1054 $record = array(
1055 'uid' => $uid,
1056 'pid' => 0, // always 0!
1057 'tstamp' => 0, // does not really matter
1058 'deleted' => 0,
1059 'title' => ($uid == 0 ? '['.$LANG->getLL('shortcut_onlineWS').']' : '['.$LANG->getLL('shortcut_offlineWS').']'),
1060 'description' => ($uid == 0 ? $LANG->getLL('shortcut_onlineWS') : $LANG->getLL('shortcut_offlineWS')),
1061 'adminusers' => '',
1062 'members' => '',
1063 'reviewers' => '',
1064 'db_mountpoints' => '', // TODO get mount points from user profile
1065 'file_mountpoints' => '', // TODO get mount points from user profile for live workspace only (uid == 0)
1066 'publish_time' => 0,
1067 'unpublish_time' => 0,
1068 'freeze' => 0,
1069 'live_edit' => ($uid == 0),
1070 'vtypes' => 0,
1071 'disable_autocreate' => 0,
1072 'swap_modes' => 0,
1073 'publish_access' => 0,
1074 'stagechg_notification' => 0
1075 );
1076 return $record;
1077 }
1078 }
1079
1080
1081 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['typo3/mod/user/ws/index.php'])) {
1082 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['typo3/mod/user/ws/index.php']);
1083 }
1084
1085
1086
1087 // Make instance:
1088 $SOBE = t3lib_div::makeInstance('SC_mod_user_ws_index');
1089 $SOBE->execute();
1090 $SOBE->init();
1091 $SOBE->main();
1092 $SOBE->printContent();
1093
1094 ?>