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