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