/** * Send an email notification to users in workspace * * @param array $stat Workspace access array (from t3lib_userauthgroup::checkWorkspace()) * @param integer $stageId New Stage number: 0 = editing, 1= just ready for review, 10 = ready for publication, -1 = rejected! * @param string $table Table name of element (or list of element names if $id is zero) * @param integer $id Record uid of element (if zero, then $table is used as reference to element(s) alone) * @param string $comment User comment sent along with action * @param t3lib_TCEmain $tcemainObj TCEmain object * @param string $notificationAlternativeRecipients Comma separated list of recipients to notificate instead of be_users selected by sys_workspace, list is generated by workspace extension module * @return void */ protected function notifyStageChange(array $stat, $stageId, $table, $id, $comment, t3lib_TCEmain $tcemainObj, $notificationAlternativeRecipients = FALSE) { $workspaceRec = t3lib_BEfunc::getRecord('sys_workspace', $stat['uid']); // So, if $id is not set, then $table is taken to be the complete element name! $elementName = $id ? $table . ':' . $id : $table; if (is_array($workspaceRec)) { // Get the new stage title from workspaces library, if workspaces extension is installed if (t3lib_extMgm::isLoaded('workspaces')) { $stageService = t3lib_div::makeInstance('Tx_Workspaces_Service_Stages'); $newStage = $stageService->getStageTitle((int) $stageId); } else { // TODO: CONSTANTS SHOULD BE USED - tx_service_workspace_workspaces // TODO: use localized labels // Compile label: switch ((int) $stageId) { case 1: $newStage = 'Ready for review'; break; case 10: $newStage = 'Ready for publishing'; break; case -1: $newStage = 'Element was rejected!'; break; case 0: $newStage = 'Rejected element was noticed and edited'; break; default: $newStage = 'Unknown state change!?'; break; } } if ($notificationAlternativeRecipients == false) { // Compile list of recipients: $emails = array(); switch ((int) $stat['stagechg_notification']) { case 1: switch ((int) $stageId) { case 1: $emails = $this->getEmailsForStageChangeNotification($workspaceRec['reviewers']); break; case 10: $emails = $this->getEmailsForStageChangeNotification($workspaceRec['adminusers'], TRUE); break; case -1: # $emails = $this->getEmailsForStageChangeNotification($workspaceRec['reviewers']); # $emails = array_merge($emails,$this->getEmailsForStageChangeNotification($workspaceRec['members'])); // List of elements to reject: $allElements = explode(',', $elementName); // Traverse them, and find the history of each foreach ($allElements as $elRef) { list($eTable, $eUid) = explode(':', $elRef); $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('log_data,tstamp,userid', 'sys_log', 'action=6 and details_nr=30 AND tablename=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($eTable, 'sys_log') . ' AND recuid=' . intval($eUid), '', 'uid DESC'); // Find all implicated since the last stage-raise from editing to review: foreach ($rows as $dat) { $data = unserialize($dat['log_data']); $emails = t3lib_div::array_merge($emails, $this->getEmailsForStageChangeNotification($dat['userid'], TRUE)); if ($data['stage'] == 1) { break; } } } break; case 0: $emails = $this->getEmailsForStageChangeNotification($workspaceRec['members']); break; default: $emails = $this->getEmailsForStageChangeNotification($workspaceRec['adminusers'], TRUE); break; } break; case 10: $emails = $this->getEmailsForStageChangeNotification($workspaceRec['adminusers'], TRUE); $emails = t3lib_div::array_merge($emails, $this->getEmailsForStageChangeNotification($workspaceRec['reviewers'])); $emails = t3lib_div::array_merge($emails, $this->getEmailsForStageChangeNotification($workspaceRec['members'])); break; } } else { $emails = array(); foreach ($notificationAlternativeRecipients as $emailAddress) { $emails[] = array('email' => $emailAddress); } } // prepare and then send the emails if (count($emails)) { // Path to record is found: list($elementTable, $elementUid) = explode(':', $elementName); $elementUid = intval($elementUid); $elementRecord = t3lib_BEfunc::getRecord($elementTable, $elementUid); $recordTitle = t3lib_BEfunc::getRecordTitle($elementTable, $elementRecord); if ($elementTable == 'pages') { $pageUid = $elementUid; } else { t3lib_BEfunc::fixVersioningPid($elementTable, $elementRecord); $pageUid = $elementUid = $elementRecord['pid']; } // fetch the TSconfig settings for the email // old way, options are TCEMAIN.notificationEmail_body/subject $TCEmainTSConfig = $tcemainObj->getTCEMAIN_TSconfig($pageUid); // these options are deprecated since TYPO3 4.5, but are still // used in order to provide backwards compatibility $emailMessage = trim($TCEmainTSConfig['notificationEmail_body']); $emailSubject = trim($TCEmainTSConfig['notificationEmail_subject']); // new way, options are // pageTSconfig: tx_version.workspaces.stageNotificationEmail.subject // userTSconfig: page.tx_version.workspaces.stageNotificationEmail.subject $pageTsConfig = t3lib_BEfunc::getPagesTSconfig($pageUid); $emailConfig = $pageTsConfig['tx_version.']['workspaces.']['stageNotificationEmail.']; $markers = array('###RECORD_TITLE###' => $recordTitle, '###RECORD_PATH###' => t3lib_BEfunc::getRecordPath($elementUid, '', 20), '###SITE_NAME###' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'], '###SITE_URL###' => t3lib_div::getIndpEnv('TYPO3_SITE_URL') . TYPO3_mainDir, '###WORKSPACE_TITLE###' => $workspaceRec['title'], '###WORKSPACE_UID###' => $workspaceRec['uid'], '###ELEMENT_NAME###' => $elementName, '###NEXT_STAGE###' => $newStage, '###COMMENT###' => $comment, '###USER_REALNAME###' => $tcemainObj->BE_USER->user['realName'], '###USER_USERNAME###' => $tcemainObj->BE_USER->user['username']); // sending the emails the old way with sprintf(), // because it was set explicitly in TSconfig if ($emailMessage && $emailSubject) { t3lib_div::deprecationLog('This TYPO3 installation uses Workspaces staging notification by setting the TSconfig options "TCEMAIN.notificationEmail_subject" / "TCEMAIN.notificationEmail_body". Please use the more flexible marker-based options tx_version.workspaces.stageNotificationEmail.message / tx_version.workspaces.stageNotificationEmail.subject'); $emailSubject = sprintf($emailSubject, $elementName); $emailMessage = sprintf($emailMessage, $markers['###SITE_NAME###'], $markers['###SITE_URL###'], $markers['###WORKSPACE_TITLE###'], $markers['###WORKSPACE_UID###'], $markers['###ELEMENT_NAME###'], $markers['###NEXT_STAGE###'], $markers['###COMMENT###'], $markers['###USER_REALNAME###'], $markers['###USER_USERNAME###'], $markers['###RECORD_PATH###'], $markers['###RECORD_TITLE###']); // filter out double email addresses $emailRecipients = array(); foreach ($emails as $recip) { $emailRecipients[$recip['email']] = $recip['email']; } $emailRecipients = implode(',', $emailRecipients); // Send one email to everybody t3lib_div::plainMailEncoded($emailRecipients, $emailSubject, $emailMessage); } else { // send an email to each individual user, to ensure the // multilanguage version of the email $emailHeaders = $emailConfig['additionalHeaders']; $emailRecipients = array(); // an array of language objects that are needed // for emails with different languages $languageObjects = array($GLOBALS['LANG']->lang => $GLOBALS['LANG']); // loop through each recipient and send the email foreach ($emails as $recipientData) { // don't send an email twice if (isset($emailRecipients[$recipientData['email']])) { continue; } $emailSubject = $emailConfig['subject']; $emailMessage = $emailConfig['message']; $emailRecipients[$recipientData['email']] = $recipientData['email']; // check if the email needs to be localized // in the users' language if (t3lib_div::isFirstPartOfStr($emailSubject, 'LLL:') || t3lib_div::isFirstPartOfStr($emailMessage, 'LLL:')) { $recipientLanguage = $recipientData['lang'] ? $recipientData['lang'] : 'default'; if (!isset($languageObjects[$recipientLanguage])) { // a LANG object in this language hasn't been // instantiated yet, so this is done here /** @var $languageObject language */ $languageObject = t3lib_div::makeInstance('language'); $languageObject->init($recipientLanguage); $languageObjects[$recipientLanguage] = $languageObject; } else { $languageObject = $languageObjects[$recipientLanguage]; } if (t3lib_div::isFirstPartOfStr($emailSubject, 'LLL:')) { $emailSubject = $languageObject->sL($emailSubject); } if (t3lib_div::isFirstPartOfStr($emailMessage, 'LLL:')) { $emailMessage = $languageObject->sL($emailMessage); } } $emailSubject = t3lib_parseHtml::substituteMarkerArray($emailSubject, $markers, '', TRUE, TRUE); $emailMessage = t3lib_parseHtml::substituteMarkerArray($emailMessage, $markers, '', TRUE, TRUE); // Send an email to the recipient t3lib_div::plainMailEncoded($recipientData['email'], $emailSubject, $emailMessage, $emailHeaders); } $emailRecipients = implode(',', $emailRecipients); } $tcemainObj->newlog2('Notification email for stage change was sent to "' . $emailRecipients . '"', $table, $id); } } }
/** * A function which can be used for load a batch of records from $table into internal memory of this object. * The function is also used to produce proper default data for new records * Ultimately the function will call renderRecord() * * @param string Table name, must be found in $TCA * @param string Comma list of id values. If $idList is "prev" then the value from $this->prevPageID is used. NOTICE: If $operation is "new", then negative ids are meant to point to a "previous" record and positive ids are PID values for new records. Otherwise (for existing records that is) it is straight forward table/id pairs. * @param string If "new", then a record with default data is returned. Further, the $id values are meant to be PID values (or if negative, pointing to a previous record). If NOT new, then the table/ids are just pointing to an existing record! * @return void * @see renderRecord() */ function fetchRecord($table, $idList, $operation) { global $TCA; if ((string) $idList == 'prev') { $idList = $this->prevPageID; } if ($TCA[$table]) { t3lib_div::loadTCA($table); // For each ID value (integer) we $ids = t3lib_div::trimExplode(',', $idList, 1); foreach ($ids as $id) { if (strcmp($id, '')) { // If ID is not blank: // For new records to be created, find default values: if ($operation == 'new') { // Default values: $newRow = array(); // Used to store default values as found here: // Default values as set in userTS: $TCAdefaultOverride = $GLOBALS['BE_USER']->getTSConfigProp('TCAdefaults'); if (is_array($TCAdefaultOverride[$table . '.'])) { foreach ($TCAdefaultOverride[$table . '.'] as $theF => $theV) { if (isset($TCA[$table]['columns'][$theF])) { $newRow[$theF] = $theV; } } } if ($id < 0) { $record = t3lib_beFunc::getRecord($table, abs($id), 'pid'); $pid = $record['pid']; unset($record); } else { $pid = intval($id); } $pageTS = t3lib_beFunc::getPagesTSconfig($pid); if (isset($pageTS['TCAdefaults.'])) { $TCAPageTSOverride = $pageTS['TCAdefaults.']; if (is_array($TCAPageTSOverride[$table . '.'])) { foreach ($TCAPageTSOverride[$table . '.'] as $theF => $theV) { if (isset($TCA[$table]['columns'][$theF])) { $newRow[$theF] = $theV; } } } } // Default values as submitted: if (is_array($this->defVals[$table])) { foreach ($this->defVals[$table] as $theF => $theV) { if (isset($TCA[$table]['columns'][$theF])) { $newRow[$theF] = $theV; } } } // Fetch default values if a previous record exists if ($id < 0 && $TCA[$table]['ctrl']['useColumnsForDefaultValues']) { // Fetches the previous record: $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid=' . abs($id) . t3lib_BEfunc::deleteClause($table)); if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { // Gets the list of fields to copy from the previous record. $fArr = t3lib_div::trimExplode(',', $TCA[$table]['ctrl']['useColumnsForDefaultValues'], 1); foreach ($fArr as $theF) { if (isset($TCA[$table]['columns'][$theF])) { $newRow[$theF] = $row[$theF]; } } } $GLOBALS['TYPO3_DB']->sql_free_result($res); } // Finally, call renderRecord: $this->renderRecord($table, uniqid('NEW'), $id, $newRow); } else { $id = intval($id); // Fetch database values $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid=' . intval($id) . t3lib_BEfunc::deleteClause($table)); if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { t3lib_BEfunc::fixVersioningPid($table, $row); $this->renderRecord($table, $id, $row['pid'], $row); $contentTable = $GLOBALS['TYPO3_CONF_VARS']['SYS']['contentTable']; $this->lockRecord($table, $id, $contentTable == $table ? $row['pid'] : 0); // Locking the pid if the table edited is the content table. } $GLOBALS['TYPO3_DB']->sql_free_result($res); } } } } }
/** * Checks access for element * * @param string Table name * @param integer Record uid * @return void */ function checkEditAccess($table, $uid) { global $BE_USER; $calcPRec = t3lib_BEfunc::getRecord($table, $uid); t3lib_BEfunc::fixVersioningPid($table, $calcPRec); if (is_array($calcPRec)) { if ($table == 'pages') { // If pages: $CALC_PERMS = $BE_USER->calcPerms($calcPRec); $hasAccess = $CALC_PERMS & 2 ? TRUE : FALSE; } else { $CALC_PERMS = $BE_USER->calcPerms(t3lib_BEfunc::getRecord('pages', $calcPRec['pid'])); // Fetching pid-record first. $hasAccess = $CALC_PERMS & 16 ? TRUE : FALSE; } // Check internals regarding access: if ($hasAccess) { $hasAccess = $BE_USER->recordEditAccessInternals($table, $calcPRec); } } else { $hasAccess = FALSE; } return $hasAccess; }
/** * Returns an array with record properties, like header and pid, based on the row * * @param string Table name * @param array Input row * @return array Output array */ function getRecordPropertiesFromRow($table, $row) { global $TCA; if ($TCA[$table]) { t3lib_BEfunc::fixVersioningPid($table, $row); $out = array('header' => $row[$TCA[$table]['ctrl']['label']], 'pid' => $row['pid'], 'event_pid' => $this->eventPid($table, isset($row['_ORIG_pid']) ? $row['t3ver_oid'] : $row['uid'], $row['pid']), 't3ver_state' => $TCA[$table]['ctrl']['versioningWS'] ? $row['t3ver_state'] : '', '_ORIG_pid' => $row['_ORIG_pid']); return $out; } }
/** * Creates the editing form with TCEforms, based on the input from GPvars. * * @return string HTML form elements wrapped in tables */ function makeEditForm() { global $BE_USER, $LANG, $TCA; // Initialize variables: $this->elementsData = array(); $this->errorC = 0; $this->newC = 0; $thePrevUid = ''; $editForm = ''; $trData = NULL; // Traverse the GPvar edit array foreach ($this->editconf as $table => $conf) { // Tables: if (is_array($conf) && $TCA[$table] && $BE_USER->check('tables_modify', $table)) { // Traverse the keys/comments of each table (keys can be a commalist of uids) foreach ($conf as $cKey => $cmd) { if ($cmd == 'edit' || $cmd == 'new') { // Get the ids: $ids = t3lib_div::trimExplode(',', $cKey, 1); // Traverse the ids: foreach ($ids as $theUid) { // Checking if the user has permissions? (Only working as a precaution, because the final permission check is always down in TCE. But it's good to notify the user on beforehand...) // First, resetting flags. $hasAccess = 1; $deniedAccessReason = ''; $deleteAccess = 0; $this->viewId = 0; // If the command is to create a NEW record...: if ($cmd == 'new') { if (intval($theUid)) { // NOTICE: the id values in this case points to the page uid onto which the record should be create OR (if the id is negativ) to a record from the same table AFTER which to create the record. // Find parent page on which the new record reside if ($theUid < 0) { // Less than zero - find parent page $calcPRec = t3lib_BEfunc::getRecord($table, abs($theUid)); $calcPRec = t3lib_BEfunc::getRecord('pages', $calcPRec['pid']); } else { // always a page $calcPRec = t3lib_BEfunc::getRecord('pages', abs($theUid)); } // Now, calculate whether the user has access to creating new records on this position: if (is_array($calcPRec)) { $CALC_PERMS = $BE_USER->calcPerms($calcPRec); // Permissions for the parent page if ($table == 'pages') { // If pages: $hasAccess = $CALC_PERMS & 8 ? 1 : 0; #$this->viewId = $calcPRec['pid']; $this->viewId = 0; } else { $hasAccess = $CALC_PERMS & 16 ? 1 : 0; $this->viewId = $calcPRec['uid']; } } } $this->dontStoreDocumentRef = 1; // Don't save this document title in the document selector if the document is new. } else { // Edit: $calcPRec = t3lib_BEfunc::getRecord($table, $theUid); t3lib_BEfunc::fixVersioningPid($table, $calcPRec); if (is_array($calcPRec)) { if ($table == 'pages') { // If pages: $CALC_PERMS = $BE_USER->calcPerms($calcPRec); $hasAccess = $CALC_PERMS & 2 ? 1 : 0; $deleteAccess = $CALC_PERMS & 4 ? 1 : 0; $this->viewId = $calcPRec['uid']; } else { $CALC_PERMS = $BE_USER->calcPerms(t3lib_BEfunc::getRecord('pages', $calcPRec['pid'])); // Fetching pid-record first. $hasAccess = $CALC_PERMS & 16 ? 1 : 0; $deleteAccess = $CALC_PERMS & 16 ? 1 : 0; $this->viewId = $calcPRec['pid']; // Adding "&L=xx" if the record being edited has a languageField with a value larger than zero! if ($TCA[$table]['ctrl']['languageField'] && $calcPRec[$TCA[$table]['ctrl']['languageField']] > 0) { $this->viewId_addParams = '&L=' . $calcPRec[$TCA[$table]['ctrl']['languageField']]; } } // Check internals regarding access: if ($hasAccess) { $hasAccess = $BE_USER->recordEditAccessInternals($table, $calcPRec); $deniedAccessReason = $BE_USER->errorMsg; } } else { $hasAccess = 0; } } if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/alt_doc.php']['makeEditForm_accessCheck'])) { foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/alt_doc.php']['makeEditForm_accessCheck'] as $_funcRef) { $_params = array('table' => $table, 'uid' => $theUid, 'cmd' => $cmd, 'hasAccess' => $hasAccess); $hasAccess = t3lib_div::callUserFunction($_funcRef, $_params, $this); } } // AT THIS POINT we have checked the access status of the editing/creation of records and we can now proceed with creating the form elements: if ($hasAccess) { $prevPageID = is_object($trData) ? $trData->prevPageID : ''; $trData = t3lib_div::makeInstance('t3lib_transferData'); $trData->addRawData = TRUE; $trData->defVals = $this->defVals; $trData->lockRecords = 1; $trData->disableRTE = !$BE_USER->isRTE(); $trData->prevPageID = $prevPageID; $trData->fetchRecord($table, $theUid, $cmd == 'new' ? 'new' : ''); // 'new' reset($trData->regTableItems_data); $rec = current($trData->regTableItems_data); $rec['uid'] = $cmd == 'new' ? uniqid('NEW') : $theUid; if ($cmd == 'new') { $rec['pid'] = $theUid == 'prev' ? $thePrevUid : $theUid; } $this->elementsData[] = array('table' => $table, 'uid' => $rec['uid'], 'pid' => $rec['pid'], 'cmd' => $cmd, 'deleteAccess' => $deleteAccess); // Now, render the form: if (is_array($rec)) { // Setting visual path / title of form: $this->generalPathOfForm = $this->tceforms->getRecordPath($table, $rec); if (!$this->storeTitle) { $this->storeTitle = $this->recTitle ? htmlspecialchars($this->recTitle) : t3lib_BEfunc::getRecordTitle($table, $rec, TRUE); } // Setting variables in TCEforms object: $this->tceforms->hiddenFieldList = ''; $this->tceforms->globalShowHelp = $this->disHelp ? 0 : 1; if (is_array($this->overrideVals[$table])) { $this->tceforms->hiddenFieldListArr = array_keys($this->overrideVals[$table]); } // Register default language labels, if any: $this->tceforms->registerDefaultLanguageData($table, $rec); // Create form for the record (either specific list of fields or the whole record): $panel = ''; if ($this->columnsOnly) { if (is_array($this->columnsOnly)) { $panel .= $this->tceforms->getListedFields($table, $rec, $this->columnsOnly[$table]); } else { $panel .= $this->tceforms->getListedFields($table, $rec, $this->columnsOnly); } } else { $panel .= $this->tceforms->getMainFields($table, $rec); } $panel = $this->tceforms->wrapTotal($panel, $rec, $table); // Setting the pid value for new records: if ($cmd == 'new') { $panel .= '<input type="hidden" name="data[' . $table . '][' . $rec['uid'] . '][pid]" value="' . $rec['pid'] . '" />'; $this->newC++; } // Display "is-locked" message: if ($lockInfo = t3lib_BEfunc::isRecordLocked($table, $rec['uid'])) { $lockedMessage = t3lib_div::makeInstance('t3lib_FlashMessage', htmlspecialchars($lockInfo['msg']), '', t3lib_FlashMessage::WARNING); t3lib_FlashMessageQueue::addMessage($lockedMessage); } // Combine it all: $editForm .= $panel; } $thePrevUid = $rec['uid']; } else { $this->errorC++; $editForm .= $LANG->sL('LLL:EXT:lang/locallang_core.php:labels.noEditPermission', 1) . '<br /><br />' . ($deniedAccessReason ? 'Reason: ' . htmlspecialchars($deniedAccessReason) . '<br /><br />' : ''); } } } } } } return $editForm; }
/** * Checking if the RTE is available/enabled for a certain table/field and if so, it returns true. * Used to determine if the RTE button should be displayed. * * @param string Table name * @param array Record row (needed, if there are RTE dependencies based on other fields in the record) * @param string Field name * @return boolean Returns true if the rich text editor would be enabled/available for the field name specified. */ function isRTEforField($table, $row, $field) { $specConf = $this->getSpecConfForField($table, $row, $field); $p = t3lib_BEfunc::getSpecConfParametersFromArray($specConf['rte_transform']['parameters']); if (isset($specConf['richtext']) && (!$p['flag'] || !$row[$p['flag']])) { t3lib_BEfunc::fixVersioningPid($table, $row); list($tscPID, $thePidValue) = t3lib_BEfunc::getTSCpid($table, $row['uid'], $row['pid']); if ($thePidValue >= 0) { // If the pid-value is not negative (that is, a pid could NOT be fetched) $RTEsetup = $GLOBALS['BE_USER']->getTSConfig('RTE', t3lib_BEfunc::getPagesTSconfig($tscPID)); $RTEtypeVal = t3lib_BEfunc::getTCAtypeValue($table, $row); $thisConfig = t3lib_BEfunc::RTEsetup($RTEsetup['properties'], $table, $field, $RTEtypeVal); if (!$thisConfig['disabled']) { return TRUE; } } } return FALSE; }
/** * Initializes language icons etc. * * param string Table name * param array Record * param string Sys language uid OR ISO language code prefixed with "v", eg. "vDA" * @return void */ function getLanguageIcon($table, $row, $sys_language_uid) { global $TCA, $LANG; $mainKey = $table . ':' . $row['uid']; if (!isset($this->cachedLanguageFlag[$mainKey])) { t3lib_BEfunc::fixVersioningPid($table, $row); list($tscPID, $thePidValue) = $this->getTSCpid($table, $row['uid'], $row['pid']); $t8Tools = t3lib_div::makeInstance('t3lib_transl8tools'); $this->cachedLanguageFlag[$mainKey] = $t8Tools->getSystemLanguages($tscPID, $this->backPath); } // Convert sys_language_uid to sys_language_uid if input was in fact a string (ISO code expected then) if (!t3lib_div::testInt($sys_language_uid)) { foreach ($this->cachedLanguageFlag[$mainKey] as $rUid => $cD) { if ('v' . $cD['ISOcode'] === $sys_language_uid) { $sys_language_uid = $rUid; } } } $out = ''; if ($this->cachedLanguageFlag[$mainKey][$sys_language_uid]['flagIcon']) { $out .= t3lib_iconWorks::getSpriteIcon($this->cachedLanguageFlag[$mainKey][$sys_language_uid]['flagIcon']); $out .= ' '; } else { if ($this->cachedLanguageFlag[$mainKey][$sys_language_uid]['title']) { $out .= '[' . $this->cachedLanguageFlag[$mainKey][$sys_language_uid]['title'] . ']'; $out .= ' '; } } return $out; }
/** * This function is called by TCEmain after a new record has been inserted into the database. * If a new content element has been created, we make sure that it is referenced by its page. * * @param string $status: The command which has been sent to processDatamap * @param string $table: The table we're dealing with * @param mixed $id: Either the record UID or a string if a new record has been created * @param array $fieldArray: The record row how it has been inserted into the database * @param object $reference: A reference to the TCEmain instance * @return void * @access public */ function processDatamap_afterDatabaseOperations ($status, $table, $id, $fieldArray, &$reference) { if ($this->debug) t3lib_div::devLog ('processDatamap_afterDatabaseOperations ', 'templavoila',0,array ($status, $table,$id,$fieldArray)); if ($GLOBALS ['TYPO3_CONF_VARS']['SC_OPTIONS']['tx_templavoila_api']['apiIsRunningTCEmain']) return; if ($table != 'tt_content') return; $templaVoilaAPI = t3lib_div::makeInstance('tx_templavoila_api'); switch ($status) { case 'new' : if (!isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tx_templavoila_tcemain']['doNotInsertElementRefsToPage'])) { t3lib_BEfunc::fixVersioningPid($table, $fieldArray); if (isset ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tx_templavoila_tcemain']['preProcessFieldArrays'][$id])) { $positionReferenceUid = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tx_templavoila_tcemain']['preProcessFieldArrays'][$id]['pid']; if ($positionReferenceUid < 0) { $neighbourFlexformPointersArr = $templaVoilaAPI->flexform_getPointersByRecord (abs($positionReferenceUid ), $fieldArray['pid']); $neighbourFlexformPointer = $neighbourFlexformPointersArr[0]; if (is_array ($neighbourFlexformPointer)) { $destinationFlexformPointer = $neighbourFlexformPointer; } } } if (!is_array ($destinationFlexformPointer)) { $mainContentAreaFieldName = $templaVoilaAPI->ds_getFieldNameByColumnPosition($fieldArray['pid'], intval($fieldArray['colPos'])); if ($mainContentAreaFieldName !== FALSE) { $sorting_field = $GLOBALS['TCA'][$table]['ctrl']['sortby']; $sorting = (!$sorting_field ? 0 : ($fieldArray[$sorting_field] ? -$fieldArray[$sorting_field] : 0)); $destinationFlexformPointer = array ( 'table' => 'pages', 'uid' => $fieldArray['pid'], 'sheet' => 'sDEF', 'sLang' => 'lDEF', 'field' => $mainContentAreaFieldName, 'vLang' => 'vDEF', 'position' => 0 ); if ($sorting < 0) { $parentRecord = t3lib_BEfunc::getRecordWSOL($destinationFlexformPointer['table'], $destinationFlexformPointer['uid'],'uid,pid,tx_templavoila_flex'); $currentReferencesArr = $templaVoilaAPI->flexform_getElementReferencesFromXML($parentRecord['tx_templavoila_flex'], $destinationFlexformPointer); if (count($currentReferencesArr)) { $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,' . $sorting_field, $table, 'uid IN (' . implode(',', $currentReferencesArr) . ')' . t3lib_BEfunc::deleteClause($table)); $sort = array($reference->substNEWwithIDs[$id] => -$sorting); foreach ($rows as $row) { $sort[$row['uid']] = $row[$sorting_field]; } asort($sort, SORT_NUMERIC); $destinationFlexformPointer['position'] = array_search($reference->substNEWwithIDs[$id], array_keys($sort)); } } } } if (is_array ($destinationFlexformPointer)) { $templaVoilaAPI->insertElement_setElementReferences ($destinationFlexformPointer, $reference->substNEWwithIDs[$id]); } } break; } // clearing the cache of all related pages - see #1332 if (method_exists($reference, 'clear_cacheCmd')) { $element = array( 'table' => $table, 'uid' => $id ); $references = tx_templavoila_div::getElementForeignReferences($element, $fieldArray['pid']); if (is_array($references) && is_array($references['pages'])) { foreach($references['pages'] as $pageUid=>$__) { $reference->clear_cacheCmd($pageUid); } } } unset ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tx_templavoila_tcemain']['preProcessFieldArrays']); }
/** * Creates the editing form with TCEforms, based on the input from GPvars. * * @return string HTML form elements wrapped in tables */ function makeEditForm() { global $BE_USER, $LANG, $TCA; // Initialize variables: $this->elementsData = array(); $this->errorC = 0; $this->newC = 0; $thePrevUid = ''; $editForm = ''; // Traverse the GPvar edit array foreach ($this->editconf as $table => $conf) { // Tables: if (is_array($conf) && $TCA[$table] && $BE_USER->check('tables_modify', $table)) { // Traverse the keys/comments of each table (keys can be a commalist of uids) foreach ($conf as $cKey => $cmd) { if ($cmd == 'edit' || $cmd == 'new') { // Get the ids: $ids = t3lib_div::trimExplode(',', $cKey, 1); // Traverse the ids: foreach ($ids as $theUid) { // Checking if the user has permissions? (Only working as a precaution, because the final permission check is always down in TCE. But it's good to notify the user on beforehand...) // First, resetting flags. $hasAccess = 1; $deniedAccessReason = ''; $deleteAccess = 0; $this->viewId = 0; // If the command is to create a NEW record...: if ($cmd == 'new') { if (intval($theUid)) { // NOTICE: the id values in this case points to the page uid onto which the record should be create OR (if the id is negativ) to a record from the same table AFTER which to create the record. // Find parent page on which the new record reside if ($theUid < 0) { // Less than zero - find parent page $calcPRec = t3lib_BEfunc::getRecord($table, abs($theUid)); $calcPRec = t3lib_BEfunc::getRecord('pages', $calcPRec['pid']); } else { // always a page $calcPRec = t3lib_BEfunc::getRecord('pages', abs($theUid)); } // Now, calculate whether the user has access to creating new records on this position: if (is_array($calcPRec)) { $CALC_PERMS = $BE_USER->calcPerms($calcPRec); // Permissions for the parent page if ($table == 'pages') { // If pages: $hasAccess = $CALC_PERMS & 8 ? 1 : 0; $this->viewId = $calcPRec['pid']; } else { $hasAccess = $CALC_PERMS & 16 ? 1 : 0; $this->viewId = $calcPRec['uid']; } } } $this->dontStoreDocumentRef = 1; // Don't save this document title in the document selector if the document is new. } else { // Edit: $calcPRec = t3lib_BEfunc::getRecord($table, $theUid); t3lib_BEfunc::fixVersioningPid($table, $calcPRec); if (is_array($calcPRec)) { if ($table == 'pages') { // If pages: $CALC_PERMS = $BE_USER->calcPerms($calcPRec); $hasAccess = $CALC_PERMS & 2 ? 1 : 0; $deleteAccess = $CALC_PERMS & 4 ? 1 : 0; $this->viewId = $calcPRec['uid']; } else { $CALC_PERMS = $BE_USER->calcPerms(t3lib_BEfunc::getRecord('pages', $calcPRec['pid'])); // Fetching pid-record first. $hasAccess = $CALC_PERMS & 16 ? 1 : 0; $deleteAccess = $CALC_PERMS & 16 ? 1 : 0; $this->viewId = $calcPRec['pid']; // Adding "&L=xx" if the record being edited has a languageField with a value larger than zero! if ($TCA[$table]['ctrl']['languageField'] && $calcPRec[$TCA[$table]['ctrl']['languageField']] > 0) { $this->viewId_addParams = '&L=' . $calcPRec[$TCA[$table]['ctrl']['languageField']]; } } // Check internals regarding access: if ($hasAccess) { $hasAccess = $BE_USER->recordEditAccessInternals($table, $calcPRec); $deniedAccessReason = $BE_USER->errorMsg; } } else { $hasAccess = 0; } } // AT THIS POINT we have checked the access status of the editing/creation of records and we can now proceed with creating the form elements: //danielp: additional permission check: // if user wants to edit/create page record but has no access to default language! if ($table == 'pages' && !$BE_USER->checkLanguageAccess(0)) { if (t3lib_extMgm::isLoaded('languagevisibility')) { require_once t3lib_extMgm::extPath("languagevisibility") . 'class.tx_languagevisibility_beservices.php'; $visibilityservice = t3lib_div::makeInstance('tx_languagevisibility_beservices'); if (!$visibilityservice->hasUserAccessToPageRecord($theUid, $cmd)) { $hasAccess = FALSE; } } } if ($hasAccess) { $prevPageID = is_object($trData) ? $trData->prevPageID : ''; $trData = t3lib_div::makeInstance('t3lib_transferData'); $trData->addRawData = TRUE; $trData->defVals = $this->defVals; $trData->lockRecords = 1; $trData->disableRTE = $this->MOD_SETTINGS['disableRTE']; $trData->prevPageID = $prevPageID; $trData->fetchRecord($table, $theUid, $cmd == 'new' ? 'new' : ''); // 'new' reset($trData->regTableItems_data); $rec = current($trData->regTableItems_data); $rec['uid'] = $cmd == 'new' ? uniqid('NEW') : $theUid; if ($cmd == 'new') { $rec['pid'] = $theUid == 'prev' ? $thePrevUid : $theUid; } $this->elementsData[] = array('table' => $table, 'uid' => $rec['uid'], 'pid' => $rec['pid'], 'cmd' => $cmd, 'deleteAccess' => $deleteAccess); // Now, render the form: if (is_array($rec)) { // Setting visual path / title of form: $this->generalPathOfForm = $this->tceforms->getRecordPath($table, $rec); if (!$this->storeTitle) { $this->storeTitle = $this->recTitle ? htmlspecialchars($this->recTitle) : t3lib_BEfunc::getRecordTitle($table, $rec, TRUE); } // Setting variables in TCEforms object: $this->tceforms->hiddenFieldList = ''; $this->tceforms->globalShowHelp = $this->disHelp ? 0 : 1; if (is_array($this->overrideVals[$table])) { $this->tceforms->hiddenFieldListArr = array_keys($this->overrideVals[$table]); } // Register default language labels, if any: $this->tceforms->registerDefaultLanguageData($table, $rec); // Create form for the record (either specific list of fields or the whole record): $panel = ''; if ($this->columnsOnly) { if (is_array($this->columnsOnly)) { $panel .= $this->tceforms->getListedFields($table, $rec, $this->columnsOnly[$table]); } else { $panel .= $this->tceforms->getListedFields($table, $rec, $this->columnsOnly); } } else { $panel .= $this->tceforms->getMainFields($table, $rec); } $panel = $this->tceforms->wrapTotal($panel, $rec, $table); // Setting the pid value for new records: if ($cmd == 'new') { $panel .= '<input type="hidden" name="data[' . $table . '][' . $rec['uid'] . '][pid]" value="' . $rec['pid'] . '" />'; $this->newC++; } // Display "is-locked" message: if ($lockInfo = t3lib_BEfunc::isRecordLocked($table, $rec['uid'])) { $lockIcon = ' <!-- Warning box: --> <table border="0" cellpadding="0" cellspacing="0" class="warningbox"> <tr> <td><img' . t3lib_iconWorks::skinImg($this->doc->backPath, 'gfx/recordlock_warning3.gif', 'width="17" height="12"') . ' alt="" /></td> <td>' . htmlspecialchars($lockInfo['msg']) . '</td> </tr> </table> '; } else { $lockIcon = ''; } // Combine it all: $editForm .= $lockIcon . $panel; } $thePrevUid = $rec['uid']; } else { $this->errorC++; $editForm .= $LANG->sL('LLL:EXT:lang/locallang_core.php:labels.noEditPermission', 1) . '<br /><br />' . ($deniedAccessReason ? 'Reason: ' . htmlspecialchars($deniedAccessReason) . '<br/><br/>' : ''); } } } } } } return $editForm; }
/** * Returns the path (visually) of a page $uid, fx. "/First page/Second page/Another subpage" * Each part of the path will be limited to $titleLimit characters * Deleted pages are filtered out. * * @param integer Page uid for which to create record path * @param string $clause is additional where clauses, eg. " * @param integer Title limit * @param integer Title limit of Full title (typ. set to 1000 or so) * @return mixed Path of record (string) OR array with short/long title if $fullTitleLimit is set. */ public static function getRecordPath($uid, $clause = '', $titleLimit = 1000, $fullTitleLimit = 0) { $loopCheck = 100; $output = $fullOutput = '/'; while ($uid != 0 && $loopCheck > 0) { $loopCheck--; $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,pid,title,deleted,t3ver_oid,t3ver_wsid,t3ver_swapmode', 'pages', 'uid=' . intval($uid) . (strlen(trim($clause)) ? ' AND ' . $clause : '')); if (is_resource($res)) { $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res); $GLOBALS['TYPO3_DB']->sql_free_result($res); t3lib_BEfunc::workspaceOL('pages', $row); if (is_array($row)) { t3lib_BEfunc::fixVersioningPid('pages', $row); if ($row['_ORIG_pid'] && $row['t3ver_swapmode'] > 0) { // Branch points $output = ' [#VEP#]' . $output; // Adding visual token - Versioning Entry Point - that tells that THIS position was where the versionized branch got connected to the main tree. I will have to find a better name or something... } $uid = $row['pid']; $output = '/' . t3lib_div::fixed_lgd_cs(strip_tags($row['title']), $titleLimit) . $output; if ($row['deleted']) { $output = '<span class="deletedPath">' . $output . '</span>'; } if ($fullTitleLimit) { $fullOutput = '/' . t3lib_div::fixed_lgd_cs(strip_tags($row['title']), $fullTitleLimit) . $fullOutput; } } else { break; } } else { break; } } if ($fullTitleLimit) { return array($output, $fullOutput); } else { return $output; } }
/** * Checks the page access rights (Code for access check mostly taken from alt_doc.php) * as well as the table access rights of the user. * * @param string $cmd: The command that sould be performed ('new' or 'edit') * @param string $table: The table to check access for * @param string $theUid: The record uid of the table * @return boolean Returns true is the user has access, or false if not */ function checkAccess($cmd, $table, $theUid) { // Checking if the user has permissions? (Only working as a precaution, because the final permission check is always down in TCE. But it's good to notify the user on beforehand...) // First, resetting flags. $hasAccess = 0; $deniedAccessReason = ''; // Admin users always have acces: if ($GLOBALS['BE_USER']->isAdmin()) { return true; } // If the command is to create a NEW record...: if ($cmd == 'new') { // If the pid is numerical, check if it's possible to write to this page: if (t3lib_div::testInt($this->inlineFirstPid)) { $calcPRec = t3lib_BEfunc::getRecord('pages', $this->inlineFirstPid); if (!is_array($calcPRec)) { return false; } $CALC_PERMS = $GLOBALS['BE_USER']->calcPerms($calcPRec); // Permissions for the parent page if ($table == 'pages') { // If pages: $hasAccess = $CALC_PERMS & 8 ? 1 : 0; // Are we allowed to create new subpages? } else { $hasAccess = $CALC_PERMS & 16 ? 1 : 0; // Are we allowed to edit content on this page? } // If the pid is a NEW... value, the access will be checked on creating the page: // (if the page with the same NEW... value could be created in TCEmain, this child record can neither) } else { $hasAccess = 1; } } else { // Edit: $calcPRec = t3lib_BEfunc::getRecord($table, $theUid); t3lib_BEfunc::fixVersioningPid($table, $calcPRec); if (is_array($calcPRec)) { if ($table == 'pages') { // If pages: $CALC_PERMS = $GLOBALS['BE_USER']->calcPerms($calcPRec); $hasAccess = $CALC_PERMS & 2 ? 1 : 0; } else { $CALC_PERMS = $GLOBALS['BE_USER']->calcPerms(t3lib_BEfunc::getRecord('pages', $calcPRec['pid'])); // Fetching pid-record first. $hasAccess = $CALC_PERMS & 16 ? 1 : 0; } // Check internals regarding access: if ($hasAccess) { $hasAccess = $GLOBALS['BE_USER']->recordEditAccessInternals($table, $calcPRec); } } } if (!$GLOBALS['BE_USER']->check('tables_modify', $table)) { $hasAccess = 0; } if (!$hasAccess) { $deniedAccessReason = $GLOBALS['BE_USER']->errorMsg; if ($deniedAccessReason) { debug($deniedAccessReason); } } return $hasAccess ? true : false; }
/** * Send an email notification to users in workspace * * @param array Workspace access array (from t3lib_userauthgroup::checkWorkspace()) * @param integer New Stage number: 0 = editing, 1= just ready for review, 10 = ready for publication, -1 = rejected! * @param string Table name of element (or list of element names if $id is zero) * @param integer Record uid of element (if zero, then $table is used as reference to element(s) alone) * @param string User comment sent along with action * @return void */ function notifyStageChange($stat, $stageId, $table, $id, $comment) { $workspaceRec = t3lib_BEfunc::getRecord('sys_workspace', $stat['uid']); $elementName = $id ? $table . ':' . $id : $table; // So, if $id is not set, then $table is taken to be the complete element name! if (is_array($workspaceRec)) { // Compile label: switch ((int) $stageId) { case 1: $newStage = 'Ready for review'; break; case 10: $newStage = 'Ready for publishing'; break; case -1: $newStage = 'Element was rejected!'; break; case 0: $newStage = 'Rejected element was noticed and edited'; break; default: $newStage = 'Unknown state change!?'; break; } // Compile list of recipients: $emails = array(); switch ((int) $stat['stagechg_notification']) { case 1: switch ((int) $stageId) { case 1: $emails = $this->notifyStageChange_getEmails($workspaceRec['reviewers']); break; case 10: $emails = $this->notifyStageChange_getEmails($workspaceRec['adminusers'], TRUE); break; case -1: # $emails = $this->notifyStageChange_getEmails($workspaceRec['reviewers']); # $emails = array_merge($emails,$this->notifyStageChange_getEmails($workspaceRec['members'])); // List of elements to reject: $allElements = explode(',', $elementName); // Traverse them, and find the history of each foreach ($allElements as $elRef) { list($eTable, $eUid) = explode(':', $elRef); $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('log_data,tstamp,userid', 'sys_log', 'action=6 and details_nr=30 AND tablename=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($eTable, 'sys_log') . ' AND recuid=' . intval($eUid), '', 'uid DESC'); // Find all implicated since the last stage-raise from editing to review: foreach ($rows as $dat) { $data = unserialize($dat['log_data']); //debug($dat['userid'],'Adds user at stage: '.$data['stage']); $emails = array_merge($emails, $this->notifyStageChange_getEmails($dat['userid'], TRUE)); if ($data['stage'] == 1) { break; } } } break; case 0: $emails = $this->notifyStageChange_getEmails($workspaceRec['members']); break; default: $emails = $this->notifyStageChange_getEmails($workspaceRec['adminusers'], TRUE); break; } break; case 10: $emails = $this->notifyStageChange_getEmails($workspaceRec['adminusers'], TRUE); $emails = array_merge($emails, $this->notifyStageChange_getEmails($workspaceRec['reviewers'])); $emails = array_merge($emails, $this->notifyStageChange_getEmails($workspaceRec['members'])); break; } $emails = array_unique($emails); // Path to record is found: list($eTable, $eUid) = explode(':', $elementName); $eUid = intval($eUid); $rr = t3lib_BEfunc::getRecord($eTable, $eUid); $recTitle = t3lib_BEfunc::getRecordTitle($eTable, $rr); if ($eTable != 'pages') { t3lib_BEfunc::fixVersioningPid($eTable, $rr); $eUid = $rr['pid']; } $path = t3lib_BEfunc::getRecordPath($eUid, '', 20); // ALternative messages: $TSConfig = $this->getTCEMAIN_TSconfig($eUid); $body = trim($TSConfig['notificationEmail_body']) ? trim($TSConfig['notificationEmail_body']) : ' At the TYPO3 site "%s" (%s) in workspace "%s" (#%s) the stage has changed for the element(s) "%11$s" (%s) at location "%10$s" in the page tree: ==> %s User Comment: "%s" State was change by %s (username: %s) '; $subject = trim($TSConfig['notificationEmail_subject']) ? trim($TSConfig['notificationEmail_subject']) : 'TYPO3 Workspace Note: Stage Change for %s'; // Send email: if (count($emails)) { $message = sprintf($body, $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'], t3lib_div::getIndpEnv('TYPO3_SITE_URL') . TYPO3_mainDir, $workspaceRec['title'], $workspaceRec['uid'], $elementName, $newStage, $comment, $this->BE_USER->user['realName'], $this->BE_USER->user['username'], $path, $recTitle); t3lib_div::plainMailEncoded(implode(',', $emails), sprintf($subject, $elementName), trim($message)); $this->newlog2('Notification email for stage change was sent to "' . implode(', ', $emails) . '"', $table, $id); } } }