Compare commits

..

4 Commits
2.3.3 ... 2.3.1

Author SHA1 Message Date
Romain Quetiez
9f50a2714a Releasing 2.3.1
SVN:2.3.1[4305]
2016-07-08 12:38:54 +00:00
Romain Quetiez
33c5839273 Releasing 2.3.1
SVN:2.3[4304]
2016-07-08 12:19:26 +00:00
Denis Flaven
9f92bc4b8a (Retrofit) 2.3.0 Regression: login_mode was broken !
SVN:2.3[4303]
2016-07-08 12:05:59 +00:00
Romain Quetiez
2af2fd0aea Creating branch 2.3 (2.3.0 + missing czech translation for the enhanced customer portal)
SVN:2.3[4299]
2016-07-08 09:30:48 +00:00
442 changed files with 9104 additions and 7325 deletions

View File

@@ -79,7 +79,7 @@ class Html2Text {
// replace   with spaces
$html = str_replace(" ", " ", $html);
$html = mb_str_replace("\xc2\xa0", " ", $html); // DO NOT USE str_replace since it breaks the "à" character which is \xc3 \xa0 in UTF-8
$html = mb_str_replace("\xa0", " ", $html); // DO NOT USE str_replace since it breaks the "à" character which is \xc3 \xa0 in UTF-8
$html = static::fixNewlines($html);

View File

@@ -202,16 +202,32 @@ EOF
// Render the tabs in the page (if any)
$this->s_content = $this->m_oTabs->RenderIntoContent($this->s_content, $this);
// Additional UI widgets to be activated inside the ajax fragment
// Important: Testing the content type is not enough because some ajax handlers have not correctly positionned the flag (e.g json response corrupted by the script)
if (($this->sContentType == 'text/html') && (preg_match('/class="date-pick"/', $this->s_content) || preg_match('/class="datetime-pick"/', $this->s_content)) )
// Additional UI widgets to be activated inside the ajax fragment ??
if (($this->sContentType == 'text/html') && (preg_match('/class="date-pick"/', $this->s_content) || preg_match('/class="datetime-pick"/', $this->s_content)) )
{
$this->add_ready_script(
<<<EOF
PrepareWidgets();
$(".date-pick").datepicker({
showOn: 'button',
buttonImage: '../images/calendar.png',
buttonImageOnly: true,
dateFormat: 'yy-mm-dd',
constrainInput: false,
changeMonth: true,
changeYear: true
});
$(".datetime-pick").datepicker({
showOn: 'button',
buttonImage: '../images/calendar.png',
buttonImageOnly: true,
dateFormat: 'yy-mm-dd 00:00:00',
constrainInput: false,
changeMonth: true,
changeYear: true
});
EOF
);
}
}
$s_captured_output = $this->ob_get_clean_safe();
if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline'))
{

View File

@@ -27,6 +27,7 @@
require_once(APPROOT.'/application/applicationcontext.class.inc.php');
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php');
require_once(APPROOT.'/application/sqlblock.class.inc.php');
require_once(APPROOT.'/application/audit.category.class.inc.php');
require_once(APPROOT.'/application/audit.rule.class.inc.php');
require_once(APPROOT.'/application/query.class.inc.php');

View File

@@ -688,7 +688,6 @@ EOF
else
{
$val = array('label' => '<span title="'.$oAttDef->GetDescription().'">'.$oAttDef->GetLabel().'</span>', 'value' => "<span id=\"field_{$sInputId}\">".$this->GetAsHTML($sAttCode)."</span>", 'comments' => $sComments, 'infos' => $sInfos);
$aFieldsMap[$sAttCode] = $sInputId;
}
}
else
@@ -1745,7 +1744,7 @@ EOF
$aEventsList[] ='change';
$sPlaceholderValue = 'placeholder="'.htmlentities(AttributeDateTime::GetFormat()->ToPlaceholder(), ENT_QUOTES, 'UTF-8').'"';
$sHTMLValue = "<input title=\"$sHelpText\" class=\"datetime-pick\" type=\"text\" size=\"19\" $sPlaceholderValue name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/>&nbsp;{$sValidationSpan}{$sReloadSpan}";
$sHTMLValue = "<input title=\"$sHelpText\" class=\"datetime-pick\" type=\"text\" size=\"15\" $sPlaceholderValue name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/>&nbsp;{$sValidationSpan}{$sReloadSpan}";
break;
case 'Duration':
@@ -3543,6 +3542,7 @@ EOF
// b) or override some of the configuration settings, using the second parameter of ckeditor()
$aConfig = array();
$sLanguage = strtolower(trim(UserRights::GetUserLanguage()));
$aConfig['font_style'] = $sLanguage;
$aConfig['language'] = $sLanguage;
$aConfig['contentsLanguage'] = $sLanguage;
$aConfig['extraPlugins'] = 'disabler';

View File

@@ -795,17 +795,9 @@ class DisplayBlock
$sCsvFile = strtolower($this->m_oFilter->GetClass()).'.csv';
$sDownloadLink = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?expression='.urlencode($this->m_oFilter->ToOQL(true)).'&format=csv&filename='.urlencode($sCsvFile);
$sLinkToToggle = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize()).'&format=csv';
// Pass the parameters via POST, since expression may be very long
$aParamsToPost = array(
'expression' => $this->m_oFilter->ToOQL(true),
'format' => 'csv',
'filename' => $sCsvFile,
'charset' => 'UTF-8',
);
if ($bAdvancedMode)
{
$sDownloadLink .= '&fields_advanced=1';
$aParamsToPost['fields_advance'] = 1;
$sChecked = 'CHECKED';
}
else
@@ -813,7 +805,7 @@ class DisplayBlock
$sLinkToToggle = $sLinkToToggle.'&advanced=1';
$sChecked = '';
}
$sAjaxLink = utils::GetAbsoluteUrlAppRoot().'webservices/export.php';
$sAjaxLink = $sDownloadLink.'&charset=UTF-8'; // Includes &fields_advanced=1 if in advanced mode
/*
$sCSVData = cmdbAbstractObject::GetSetAsCSV($this->m_oSet, array('fields_advanced' => $bAdvancedMode));
@@ -864,8 +856,7 @@ class DisplayBlock
$sHtml .= "<div id=\"csv_content_loading\"><div style=\"width: 250px; height: 20px; background: url(../setup/orange-progress.gif); border: 1px #999 solid; margin-left:auto; margin-right: auto; text-align: center;\">".Dict::S('UI:Loading')."</div></div><textarea id=\"csv_content\" style=\"display:none;\">\n";
//$sHtml .= htmlentities($sCSVData, ENT_QUOTES, 'UTF-8');
$sHtml .= "</textarea>\n";
$sJsonParams = json_encode($aParamsToPost);
$oPage->add_ready_script("$.post('$sAjaxLink', $sJsonParams, function(data) { $('#csv_content').html(data); $('#csv_content_loading').hide(); $('#csv_content').show();} );");
$oPage->add_ready_script("$.post('$sAjaxLink', {}, function(data) { $('#csv_content').html(data); $('#csv_content_loading').hide(); $('#csv_content').show();} );");
break;
case 'modify':
@@ -1015,12 +1006,6 @@ var chart = c3.generate({
},
axis: {
x: {
tick: {
culling: {max: 25}, // Maximum 24 labels on x axis (2 years).
centered: true,
rotate: 90,
multiline: false
},
type: 'category' // this needed to load string x value
}
},
@@ -1072,7 +1057,6 @@ var chart = c3.generate({
},
legend: {
show: true,
position: 'right',
},
tooltip: {
format: {

View File

@@ -881,7 +881,7 @@ class DesignerTextField extends DesignerFormField
$this->sValidationPattern = $sValidationPattern;
}
public function SetForbiddenValues($aValues, $sExplain, $bCaseSensitive = true)
public function SetForbiddenValues($aValues, $sExplain)
{
$aForbiddenValues = $aValues;
@@ -893,7 +893,7 @@ class DesignerTextField extends DesignerFormField
}
$this->aForbiddenValues[] = array('values' => $aForbiddenValues, 'message' => $sExplain, 'case_sensitive' => $bCaseSensitive);
$this->aForbiddenValues[] = array('values' => $aForbiddenValues, 'message' => $sExplain);
}
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
@@ -1367,36 +1367,6 @@ class RunTimeIconSelectionField extends DesignerIconSelectionField
}
static protected function FindIconsOnDisk($sBaseDir, $sDir = '')
{
$aFiles = null;
$sKey = $sBaseDir.'/'.$sDir;
$sShortKey = abs(crc32($sKey));
$sCacheFile = utils::GetCachePath().'available-icons-'.$sShortKey.'.php';
$sCacheClass = 'AvailableIcons_'.$sShortKey;
if (file_exists($sCacheFile))
{
require_once($sCacheFile);
if ($sCacheClass::$sKey === $sKey) // crc32 collision detection
{
$aFiles = $sCacheClass::$aIconFiles;
}
}
if ($aFiles === null)
{
$aFiles = self::_FindIconsOnDisk($sBaseDir, $sDir);
$sAvailableIcons = '<?php'.PHP_EOL;
$sAvailableIcons .= '// Generated and used by '.__METHOD__.PHP_EOL;
$sAvailableIcons .= 'class '.$sCacheClass.PHP_EOL;
$sAvailableIcons .= '{'.PHP_EOL;
$sAvailableIcons .= ' static $sKey = '.var_export($sKey, true).';'.PHP_EOL;
$sAvailableIcons .= ' static $aIconFiles = '.var_export($aFiles, true).';'.PHP_EOL;
$sAvailableIcons .= '}'.PHP_EOL;
file_put_contents($sCacheFile, $sAvailableIcons, LOCK_EX);
}
return $aFiles;
}
static protected function _FindIconsOnDisk($sBaseDir, $sDir = '')
{
$aResult = array();
// Populate automatically the list of icon files
@@ -1408,7 +1378,7 @@ class RunTimeIconSelectionField extends DesignerIconSelectionField
if (($sFile != '.') && ($sFile != '..') && ($sFile != 'lifecycle') && is_dir($sBaseDir.'/'.$sDir.'/'.$sFile))
{
$sDirSubPath = ($sDir == '') ? $sFile : $sDir.'/'.$sFile;
$aResult = array_merge($aResult, self::_FindIconsOnDisk($sBaseDir, $sDirSubPath));
$aResult = array_merge($aResult, self::FindIconsOnDisk($sBaseDir, $sDirSubPath));
}
if (preg_match("/\.(png|jpg|jpeg|gif)$/i", $sFile, $aMatches)) // png, jp(e)g and gif are considered valid
{

View File

@@ -191,8 +191,7 @@ EOF;
$sJSDatePickerOptions = json_encode($aPickerOptions);
// Time picker additional options
$aPickerOptions['showOn'] = '';
$aPickerOptions['buttonImage'] = null;
$aPickerOptions['timeFormat'] = $oTimeFormat->ToDatePicker();
$aPickerOptions['controlType'] = 'select';
$aPickerOptions['closeText'] = Dict::S('UI:Button:Ok');
@@ -209,39 +208,7 @@ EOF;
}";
$sJSDateTimePickerOptions = substr($sJSDateTimePickerOptions, 0, -1).$aMoreJSOptions;
}
$this->add_script(
<<< EOF
function PrepareWidgets()
{
// note: each action implemented here must be idempotent,
// because this helper function might be called several times on a given page
$(".date-pick").datepicker($sJSDatePickerOptions);
// Hack for the date and time picker addon issue on Chrome (see #1305)
// The workaround is to instantiate the widget on demand
// It relies on the same markup, thus reverting to the original implementation should be straightforward
$(".datetime-pick:not(.is-widget-ready)").each(function(){
var oInput = this;
$(oInput).addClass('is-widget-ready');
$('<img class="datetime-pick-button" src="../images/calendar.png">')
.insertAfter($(this))
.on('click', function(){
$(oInput)
.datetimepicker($sJSDateTimePickerOptions)
.datetimepicker('show')
.datetimepicker('option', 'onClose', function(dateText,inst){
$(oInput).datetimepicker('destroy');
})
.on('click keypress', function(){
$(oInput).datetimepicker('hide');
});
});
});
}
EOF
);
$this->m_sInitScript =
<<< EOF
try
@@ -477,7 +444,8 @@ EOF
// End of Tabs handling
PrepareWidgets();
$(".date-pick").datepicker($sJSDatePickerOptions);
$(".datetime-pick").datetimepicker($sJSDateTimePickerOptions);
// Make sortable, everything that claims to be sortable
$('.sortable').sortable( {axis: 'y', cursor: 'move', handle: '.drag_handle', stop: function()

View File

@@ -19,7 +19,7 @@
/**
* Class PortalWebPage
*
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @copyright Copyright (C) 2010-2013 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -96,88 +96,15 @@ class PortalWebPage extends NiceWebPage
$this->add_linked_script("../js/ckeditor/ckeditor.js");
$this->add_linked_script("../js/ckeditor/adapters/jquery.js");
$this->add_linked_script("../js/jquery-ui-timepicker-addon.js");
$this->add_linked_script("../js/jquery-ui-timepicker-addon-i18n.min.js");
$this->add_linked_stylesheet("../css/jquery-ui-timepicker-addon.css");
$sJSDisconnectedMessage = json_encode(Dict::S('UI:DisconnectedDlgMessage'));
$sJSTitle = json_encode(Dict::S('UI:DisconnectedDlgTitle'));
$sJSLoginAgain = json_encode(Dict::S('UI:LoginAgain'));
$sJSStayOnThePage = json_encode(Dict::S('UI:StayOnThePage'));
$aDaysMin = array(Dict::S('DayOfWeek-Sunday-Min'), Dict::S('DayOfWeek-Monday-Min'), Dict::S('DayOfWeek-Tuesday-Min'), Dict::S('DayOfWeek-Wednesday-Min'),
Dict::S('DayOfWeek-Thursday-Min'), Dict::S('DayOfWeek-Friday-Min'), Dict::S('DayOfWeek-Saturday-Min'));
$aMonthsShort = array(Dict::S('Month-01-Short'), Dict::S('Month-02-Short'), Dict::S('Month-03-Short'), Dict::S('Month-04-Short'), Dict::S('Month-05-Short'), Dict::S('Month-06-Short'),
Dict::S('Month-07-Short'), Dict::S('Month-08-Short'), Dict::S('Month-09-Short'), Dict::S('Month-10-Short'), Dict::S('Month-11-Short'), Dict::S('Month-12-Short'));
$sTimeFormat = AttributeDateTime::GetFormat()->ToTimeFormat();
$oTimeFormat = new DateTimeFormat($sTimeFormat);
$sJSLangShort = json_encode(strtolower(substr(Dict::GetUserLanguage(), 0, 2)));
// Date picker options
$aPickerOptions = array(
'showOn' => 'button',
'buttonImage' => '../images/calendar.png',
'buttonImageOnly' => true,
'dateFormat' => AttributeDate::GetFormat()->ToDatePicker(),
'constrainInput' => false,
'changeMonth' => true,
'changeYear' => true,
'dayNamesMin' => $aDaysMin,
'monthNamesShort' => $aMonthsShort,
'firstDay' => (int) Dict::S('Calendar-FirstDayOfWeek'),
);
$sJSDatePickerOptions = json_encode($aPickerOptions);
// Time picker additional options
$aPickerOptions['showOn'] = '';
$aPickerOptions['buttonImage'] = null;
$aPickerOptions['timeFormat'] = $oTimeFormat->ToDatePicker();
$aPickerOptions['controlType'] = 'select';
$aPickerOptions['closeText'] = Dict::S('UI:Button:Ok');
$sJSDateTimePickerOptions = json_encode($aPickerOptions);
if ($sJSLangShort != '"en"')
{
// More options that cannot be passed via json_encode since they must be evaluated client-side
$aMoreJSOptions = ",
'timeText': $.timepicker.regional[$sJSLangShort].timeText,
'hourText': $.timepicker.regional[$sJSLangShort].hourText,
'minuteText': $.timepicker.regional[$sJSLangShort].minuteText,
'secondText': $.timepicker.regional[$sJSLangShort].secondText,
'currentText': $.timepicker.regional[$sJSLangShort].currentText
}";
$sJSDateTimePickerOptions = substr($sJSDateTimePickerOptions, 0, -1).$aMoreJSOptions;
}
$this->add_script(
<<< EOF
function PrepareWidgets()
{
// note: each action implemented here must be idempotent,
// because this helper function might be called several times on a given page
$(".date-pick").datepicker($sJSDatePickerOptions);
// Hack for the date and time picker addon issue on Chrome (see #1305)
// The workaround is to instantiate the widget on demand
// It relies on the same markup, thus reverting to the original implementation should be straightforward
$(".datetime-pick:not(.is-widget-ready)").each(function(){
var oInput = this;
$(oInput).addClass('is-widget-ready');
$('<img class="datetime-pick-button" src="../images/calendar.png">')
.insertAfter($(this))
.on('click', function(){
$(oInput)
.datetimepicker($sJSDateTimePickerOptions)
.datetimepicker('show')
.datetimepicker('option', 'onClose', function(dateText,inst){
$(oInput).datetimepicker('destroy');
})
.on('click keypress', function(){
$(oInput).datetimepicker('hide');
});
});
});
}
EOF
);
$sJSDaysMin = json_encode(array(Dict::S('DayOfWeek-Sunday-Min'), Dict::S('DayOfWeek-Monday-Min'), Dict::S('DayOfWeek-Tuesday-Min'), Dict::S('DayOfWeek-Wednesday-Min'),
Dict::S('DayOfWeek-Thursday-Min'), Dict::S('DayOfWeek-Friday-Min'), Dict::S('DayOfWeek-Saturday-Min')));
$sJSMonthsShort = json_encode(array(Dict::S('Month-01-Short'), Dict::S('Month-02-Short'), Dict::S('Month-03-Short'), Dict::S('Month-04-Short'), Dict::S('Month-05-Short'), Dict::S('Month-06-Short'),
Dict::S('Month-07-Short'), Dict::S('Month-08-Short'), Dict::S('Month-09-Short'), Dict::S('Month-10-Short'), Dict::S('Month-11-Short'), Dict::S('Month-12-Short')));
$iFirstDayOfWeek = (int) Dict::S('Calendar-FirstDayOfWeek');
$this->add_ready_script(
<<<EOF
@@ -219,10 +146,34 @@ try
}
});
PrepareWidgets();
$(".date-pick").datepicker({
showOn: 'button',
buttonImage: '../images/calendar.png',
buttonImageOnly: true,
dateFormat: 'yy-mm-dd',
constrainInput: false,
changeMonth: true,
changeYear: true,
dayNamesMin: $sJSDaysMin,
monthNamesShort: $sJSMonthsShort,
firstDay: $iFirstDayOfWeek
});
$(".datetime-pick").datepicker({
showOn: 'button',
buttonImage: '../images/calendar.png',
buttonImageOnly: true,
dateFormat: 'yy-mm-dd 00:00:00',
constrainInput: false,
changeMonth: true,
changeYear: true,
dayNamesMin: $sJSDaysMin,
monthNamesShort: $sJSMonthsShort,
firstDay: $iFirstDayOfWeek
});
//$('.resizable').resizable(); // Make resizable everything that claims to be resizable !
$('.caselog_header').click( function () { $(this).toggleClass('open').next('.caselog_entry,.caselog_entry_html').toggle(); });
$('.caselog_header').click( function () { $(this).toggleClass('open').next('.caselog_entry_html').toggle(); });
$(document).ajaxSend(function(event, jqxhr, options) {
jqxhr.setRequestHeader('X-Combodo-Ajax', 'true');

View File

@@ -0,0 +1,531 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* SqlBlock - display tables or charts, given an SQL query - use cautiously!
*
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/pages/php-ofc-library/open-flash-chart.php');
/**
* Helper class to design optimized dashboards, based on an SQL query
*
*/
class SqlBlock
{
protected $m_sQuery;
protected $m_aColumns;
protected $m_sTitle;
protected $m_sType;
protected $m_aParams;
public function __construct($sQuery, $aColumns, $sTitle, $sType, $aParams = array())
{
$this->m_sQuery = $sQuery;
$this->m_aColumns = $aColumns;
$this->m_sTitle = $sTitle;
$this->m_sType = $sType;
$this->m_aParams = $aParams;
}
/**
* Constructs a SqlBlock object from an XML template
/*
*
* <sqlblock>
* <sql>SELECT date_format(start_date, '%d') AS Date, count(*) AS Count FROM ticket WHERE DATE_SUB(NOW(), INTERVAL 15 DAY) &lt; start_date AND finalclass = 'UserIssue' GROUP BY date_format(start_date, '%d') AND $CONDITION(param1, ticket.org_id)$</sql>
* <type>table</type>
* <title>UserRequest:Overview-Title</title>
* <parameter>
* <name>param1</name>
* <type>context</type>
* <mapping>org_id</mapping>
* </parameter>
* <column>
* <name>Date</name>
* <label>UserRequest:Overview-Date</label>
* <drilldown></drilldown>
* </column>
* <column>
* <name>Count</name>
* <label>UserRequest:Overview-Count</label>
* <drilldown>SELECT UserIssue WHERE date_format(start_date, '%d') = :Date</drilldown>
* </column>
* </sqlblock>
*
* Tags
* - sql: a (My)SQL query. Do not forget to use html entities (e.g. &lt; for <)
* - type: table (default), bars or pie. If bars or pie is selected only the two first columns are taken into account.
* - title: optional title, typed in clear or given as a dictionnary entry
* - parameter: specifies how to map the context parameters (namely org_id) to a given named parameter in the query.
* The expression $CONDITION(<param_name>, <sql_column_name>) will be automatically replaced by:
* either the string "1" if there is no restriction on the organisation in iTop
* or the string "(<sql_column_name>=<value_of_org_id>)" if there is a limitation to one organizations in iTop
* or the string "(<sql_column_name> IN (<values_of_org_id>))" if there is a limitation to a given set of organizations in iTop
* - column: specification of a column (not displayed if omitted)
* - column / name: name of the column in the SQL query (use aliases)
* - column / label: label, typed in clear or given as a dictionnary entry
* - column / drilldown: NOT IMPLEMENTED YET - OQL with parameters corresponding to column names (in the query)
*
* @param $sTemplate string The XML template
* @return DisplayBlock The DisplayBlock object, or null if the template is invalid
*/
public static function FromTemplate($sTemplate)
{
$oXml = simplexml_load_string('<root>'.$sTemplate.'</root>', 'SimpleXMLElement', LIBXML_NOCDATA);
if (false)
{
// Debug
echo "<pre>\n";
print_r($oXml);
echo "</pre>\n";
}
if (isset($oXml->title))
{
$sTitle = (string)$oXml->title;
}
if (isset($oXml->type))
{
$sType = (string)$oXml->type;
}
else
{
$sType = 'table';
}
if (!isset($oXml->sql))
{
throw new Exception('Missing tag "sql" in sqlblock');
}
$sQuery = (string)$oXml->sql;
$aColumns = array();
if (isset($oXml->column))
{
foreach ($oXml->column AS $oColumnData)
{
if (!isset($oColumnData->name))
{
throw new Exception("Missing tag 'name' in sqlblock/column");
}
$sName = (string) $oColumnData->name;
if (strlen($sName) == 0)
{
throw new Exception("Empty tag 'name' in sqlblock/column");
}
$aColumns[$sName] = array();
if (isset($oColumnData->label))
{
$sLabel = (string)$oColumnData->label;
if (strlen($sLabel) > 0)
{
$aColumns[$sName]['label'] = Dict::S($sLabel);
}
}
if (isset($oColumnData->drilldown))
{
$sDrillDown = (string)$oColumnData->drilldown;
if (strlen($sDrillDown) > 0)
{
$aColumns[$sName]['drilldown'] = $sDrillDown;
}
}
}
}
$aParams = array();
if (isset($oXml->parameter))
{
foreach ($oXml->parameter AS $oParamData)
{
if (!isset($oParamData->name))
{
throw new Exception("Missing tag 'name' for parameter in sqlblock/column");
}
$sName = (string) $oParamData->name;
if (strlen($sName) == 0)
{
throw new Exception("Empty tag 'name' for parameter in sqlblock/column");
}
if (!isset($oParamData->mapping))
{
throw new Exception("Missing tag 'mapping' for parameter in sqlblock/column");
}
$sMapping = (string) $oParamData->mapping;
if (strlen($sMapping) == 0)
{
throw new Exception("Empty tag 'mapping' for parameter in sqlblock/column");
}
if (isset($oParamData->type))
{
$sParamType = $oParamData->type;
}
else
{
$sParamType = 'context';
}
$aParams[$sName] = array('mapping' => $sMapping, 'type' => $sParamType);
}
}
return new SqlBlock($sQuery, $aColumns, $sTitle, $sType, $aParams);
}
/**
* Applies the defined parameters into the SQL query
* @return string the SQL query to execute
*/
public function BuildQuery()
{
$oAppContext = new ApplicationContext();
$sQuery = $this->m_sQuery;
$sQuery = str_replace('$DB_PREFIX$', MetaModel::GetConfig()->GetDBSubname(), $sQuery); // put the tables DB prefix (if any)
foreach($this->m_aParams as $sName => $aParam)
{
if ($aParam['type'] == 'context')
{
$sSearchPattern = '/\$CONDITION\('.$sName.',([^\)]+)\)\$/';
$value = $oAppContext->GetCurrentValue($aParam['mapping']);
if (empty($value))
{
$sSQLExpr = '(1)';
}
else
{
// Special case for managing the hierarchy of organizations
if (($aParam['mapping'] == 'org_id') && ( MetaModel::IsValidClass('Organization')))
{
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization');
if ($sHierarchicalKeyCode != false)
{
// organizations are in hierarchy... gather all the orgs below the given one...
$sOQL = "SELECT Organization AS node JOIN Organization AS root ON node.$sHierarchicalKeyCode BELOW root.id WHERE root.id = :value";
$oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL), array(), array('value' => $value));
$aOrgIds = array();
while($oOrg = $oSet->Fetch())
{
$aOrgIds[]= $oOrg->GetKey();
}
$sSQLExpr = '($1 IN('.implode(',', $aOrgIds).'))';
}
else
{
$sSQLExpr = '($1 = '.CMDBSource::Quote($value).')';
}
}
else
{
$sSQLExpr = '($1 = '.CMDBSource::Quote($value).')';
}
}
$sQuery = preg_replace($sSearchPattern, $sSQLExpr, $sQuery);
}
}
return $sQuery;
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
if (empty($aExtraParams['currentId']))
{
$sId = 'sqlblock_'.$oPage->GetUniqueId(); // Works only if the page is not an Ajax one !
}
else
{
$sId = $aExtraParams['currentId'];
}
// $oPage->add($this->GetRenderContent($oPage, $aExtraParams, $sId));
$sQuery = $this->BuildQuery();
$res = CMDBSource::Query($sQuery);
$aQueryCols = CMDBSource::GetColumns($res);
// Prepare column definitions (check + give default values)
//
foreach($this->m_aColumns as $sName => $aColumnData)
{
if (!in_array($sName, $aQueryCols))
{
throw new Exception("Unknown column name '$sName' in sqlblock column");
}
if (!isset($aColumnData['label']))
{
$this->m_aColumns[$sName]['label'] = $sName;
}
if (isset($aColumnData['drilldown']) && !empty($aColumnData['drilldown']))
{
// Check if the OQL is valid
try
{
$this->m_aColumns[$sName]['filter'] = DBObjectSearch::FromOQL($aColumnData['drilldown']);
}
catch(OQLException $e)
{
unset($aColumnData['drilldown']);
}
}
}
if (strlen($this->m_sTitle) > 0)
{
$oPage->add("<h2>".Dict::S($this->m_sTitle)."</h2>\n");
}
switch ($this->m_sType)
{
case 'bars':
case 'pie':
$aColNames = array_keys($this->m_aColumns);
$sXColName = $aColNames[0];
$sYColName = $aColNames[1];
$aData = array();
$aRows = array();
while($aRow = CMDBSource::FetchArray($res))
{
$aData[$aRow[$sXColName]] = $aRow[$sYColName];
$aRows[$aRow[$sXColName]] = $aRow;
}
$this->RenderChart($oPage, $sId, $aData, $this->m_aColumns[$sYColName]['drilldown'], $aRows);
break;
default:
case 'table':
$oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink();
if (!empty($sContext))
{
$sContext = '&'.$sContext;
}
$aDisplayConfig = array();
foreach($this->m_aColumns as $sName => $aColumnData)
{
$aDisplayConfig[$sName] = array('label' => $aColumnData['label'], 'description' => '');
}
$aDisplayData = array();
while($aRow = CMDBSource::FetchArray($res))
{
$aSQLColNames = array_keys($aRow);
$aDisplayRow = array();
foreach($this->m_aColumns as $sName => $aColumnData)
{
if (isset($aColumnData['filter']))
{
$sFilter = $aColumnData['drilldown'];
$sClass = $aColumnData['filter']->GetClass();
$sFilter = str_replace('SELECT '.$sClass, '', $sFilter);
foreach($aSQLColNames as $sColName)
{
$sFilter = str_replace(':'.$sColName, "'".addslashes( $aRow[$sColName] )."'", $sFilter);
}
$sURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search_oql&search_form=0&oql_class='.$sClass.'&oql_clause='.urlencode($sFilter).'&format=html'.$sContext;
$aDisplayRow[$sName] = '<a href="'.$sURL.'">'.$aRow[$sName]."</a>";
}
else
{
$aDisplayRow[$sName] = $aRow[$sName];
}
}
$aDisplayData[] = $aDisplayRow;
}
$oPage->table($aDisplayConfig, $aDisplayData);
break;
}
}
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
{
$sHtml = '';
return $sHtml;
}
protected function RenderChart($oPage, $sId, $aValues, $sDrillDown = '', $aRows = array())
{
// 1- Compute Open Flash Chart data
//
$aValueKeys = array();
$index = 0;
if ((count($aValues) > 0) && ($sDrillDown != ''))
{
$oFilter = DBObjectSearch::FromOQL($sDrillDown);
$sClass = $oFilter->GetClass();
$sOQLClause = str_replace('SELECT '.$sClass, '', $sDrillDown);
$aSQLColNames = array_keys(current($aRows)); // Read the list of columns from the current (i.e. first) element of the array
$oAppContext = new ApplicationContext();
$sURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search_oql&search_form=0&oql_class='.$sClass.'&format=html&'.$oAppContext->GetForLink().'&oql_clause=';
}
$aURLs = array();
foreach($aValues as $key => $value)
{
// Make sure that values are integers (so that max() will work....)
// and build an array of STRING with the keys (numeric keys are transformed into string by PHP :-(
$aValues[$key] = (int)$value;
$aValueKeys[] = (string)$key;
// Build the custom query for the 'drill down' on each element
if ($sDrillDown != '')
{
$sFilter = $sOQLClause;
foreach($aSQLColNames as $sColName)
{
$sFilter = str_replace(':'.$sColName, "'".addslashes( $aRows[$key][$sColName] )."'", $sFilter);
$aURLs[$index] = $sURL.urlencode($sFilter);
}
}
$index++;
}
$oChart = new open_flash_chart();
if ($this->m_sType == 'bars')
{
$oChartElement = new bar_glass();
if (count($aValues) > 0)
{
$maxValue = max($aValues);
}
else
{
$maxValue = 1;
}
$oYAxis = new y_axis();
$aMagicValues = array(1,2,5,10);
$iMultiplier = 1;
$index = 0;
$iTop = $aMagicValues[$index % count($aMagicValues)]*$iMultiplier;
while($maxValue > $iTop)
{
$index++;
$iTop = $aMagicValues[$index % count($aMagicValues)]*$iMultiplier;
if (($index % count($aMagicValues)) == 0)
{
$iMultiplier = $iMultiplier * 10;
}
}
//echo "oYAxis->set_range(0, $iTop, $iMultiplier);\n";
$oYAxis->set_range(0, $iTop, $iMultiplier);
$oChart->set_y_axis( $oYAxis );
$aBarValues = array();
foreach($aValues as $iValue)
{
$oBarValue = new bar_value($iValue);
$oBarValue->on_click("ofc_drilldown_{$sId}");
$aBarValues[] = $oBarValue;
}
$oChartElement->set_values($aBarValues);
//$oChartElement->set_values(array_values($aValues));
$oXAxis = new x_axis();
$oXLabels = new x_axis_labels();
// set them vertical
$oXLabels->set_vertical();
// set the label text
$oXLabels->set_labels($aValueKeys);
// Add the X Axis Labels to the X Axis
$oXAxis->set_labels( $oXLabels );
$oChart->set_x_axis( $oXAxis );
}
else
{
$oChartElement = new pie();
$oChartElement->set_start_angle( 35 );
$oChartElement->set_animate( true );
$oChartElement->set_tooltip( '#label# - #val# (#percent#)' );
$oChartElement->set_colours( array('#FF8A00', '#909980', '#2C2B33', '#CCC08D', '#596664') );
$aData = array();
foreach($aValues as $sValue => $iValue)
{
$oPieValue = new pie_value($iValue, $sValue); //@@ BUG: not passed via ajax !!!
$oPieValue->on_click("ofc_drilldown_{$sId}");
$aData[] = $oPieValue;
}
$oChartElement->set_values( $aData );
$oChart->x_axis = null;
}
// Title given in HTML
//$oTitle = new title($this->m_sTitle);
//$oChart->set_title($oTitle);
$oChart->set_bg_colour('#FFFFFF');
$oChart->add_element( $oChartElement );
$sData = $oChart->toPrettyString();
$sData = json_encode($sData);
// 2- Declare the Javascript function that will render the chart data\
//
$oPage->add_script(
<<< EOF
function ofc_get_data_{$sId}()
{
return $sData;
}
EOF
);
if (count($aURLs) > 0)
{
$sURLList = '';
foreach($aURLs as $index => $sURL)
{
$sURLList .= "\taURLs[$index] = '".addslashes($sURL)."';\n";
}
$oPage->add_script(
<<< EOF
function ofc_drilldown_{$sId}(index)
{
var aURLs = new Array();
{$sURLList}
var sURL = aURLs[index];
window.location.href = sURL; // Navigate !
}
EOF
);
}
// 3- Insert the Open Flash chart
//
$oPage->add("<div id=\"$sId\"><div>\n");
$oPage->add_ready_script(
<<<EOF
swfobject.embedSWF( "../images/open-flash-chart.swf",
"{$sId}",
"100%", "300","9.0.0",
"expressInstall.swf",
{"get-data":"ofc_get_data_{$sId}", "id":"{$sId}"},
{'wmode': 'transparent'}
);
EOF
);
}
}
?>

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2016 Combodo SARL
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,8 +20,9 @@
* Class UIHTMLEditorWidget
* UI wdiget for displaying and editing one-way encrypted passwords
*
* @author Phil Eddies
* @author Romain Quetiez
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -98,26 +99,9 @@ class UIHTMLEditorWidget
// Could also be bound to 'instanceReady.ckeditor'
$oPage->add_ready_script("$('#$iId').bind('validate', function(evt, sFormId) { return ValidateCKEditField('$iId', '', {$this->m_sMandatory}, sFormId, '') } );\n");
$oPage->add_ready_script(
<<<EOF
$('#$iId').bind('update', function(evt){
BlockField('cke_$iId', $('#$iId').attr('disabled'));
//Delayed execution - ckeditor must be properly initialized before setting readonly
var retryCount = 0;
var oMe = $('#$iId');
var delayedSetReadOnly = function () {
if (oMe.data('ckeditorInstance').editable() == undefined && retryCount++ < 10) {
setTimeout(delayedSetReadOnly, retryCount * 100); //Wait a while longer each iteration
}
else
{
oMe.data('ckeditorInstance').setReadOnly(oMe.prop('disabled'));
}
};
setTimeout(delayedSetReadOnly, 50);
});
EOF
);
$oPage->add_ready_script("$('#$iId').bind('update', function() { BlockField('cke_$iId', $('#$iId').attr('disabled')); $(this).data('ckeditorInstance').setReadOnly($(this).prop('disabled')); } );\n");
return $sHtmlValue;
}
}
?>

View File

@@ -163,10 +163,38 @@ class UILinksWidget
$aFieldsMap[$sFieldCode] = $sSafeId;
}
$sState = '';
$sJSDaysMin = json_encode(array(Dict::S('DayOfWeek-Sunday-Min'), Dict::S('DayOfWeek-Monday-Min'), Dict::S('DayOfWeek-Tuesday-Min'), Dict::S('DayOfWeek-Wednesday-Min'),
Dict::S('DayOfWeek-Thursday-Min'), Dict::S('DayOfWeek-Friday-Min'), Dict::S('DayOfWeek-Saturday-Min')));
$sJSMonthsShort = json_encode(array(Dict::S('Month-01-Short'), Dict::S('Month-02-Short'), Dict::S('Month-03-Short'), Dict::S('Month-04-Short'), Dict::S('Month-05-Short'), Dict::S('Month-06-Short'),
Dict::S('Month-07-Short'), Dict::S('Month-08-Short'), Dict::S('Month-09-Short'), Dict::S('Month-10-Short'), Dict::S('Month-11-Short'), Dict::S('Month-12-Short')));
$iFirstDayOfWeek = (int) Dict::S('Calendar-FirstDayOfWeek');
$oP->add_script(
<<<EOF
PrepareWidgets();
$(".date-pick").datepicker({
showOn: 'button',
buttonImage: '../images/calendar.png',
buttonImageOnly: true,
dateFormat: 'yy-mm-dd',
constrainInput: false,
changeMonth: true,
changeYear: true,
dayNamesMin: $sJSDaysMin,
monthNamesShort: $sJSMonthsShort,
firstDay: $iFirstDayOfWeek
});
$(".datetime-pick").datepicker({
showOn: 'button',
buttonImage: '../images/calendar.png',
buttonImageOnly: true,
dateFormat: 'yy-mm-dd 00:00:00',
constrainInput: false,
changeMonth: true,
changeYear: true,
dayNamesMin: $sJSDaysMin,
monthNamesShort: $sJSMonthsShort,
firstDay: $iFirstDayOfWeek
});
EOF
);
}

View File

@@ -437,45 +437,6 @@ class utils
return $iReturn;
}
/**
* Format a value into a more friendly format (KB, MB, GB, TB) instead a juste a Bytes amount.
*
* @param type $value
* @return string
*/
public static function BytesToFriendlyFormat($value)
{
$sReturn = '';
// Kilobytes
if ($value >= 1024)
{
$sReturn = 'K';
$value = $value / 1024;
}
// Megabytes
if ($value >= 1024)
{
$sReturn = 'M';
$value = $value / 1024;
}
// Gigabytes
if ($value >= 1024)
{
$sReturn = 'G';
$value = $value / 1024;
}
// Terabytes
if ($value >= 1024)
{
$sReturn = 'T';
$value = $value / 1024;
}
$value = round($value, 1);
return $value . '' . $sReturn . 'B';
}
/**
* Helper function to convert a string to a date, given a format specification. It replaces strtotime which does not allow for specifying a date in a french format (for instance)
* Example: StringToTime('01/05/11 12:03:45', '%d/%m/%y %H:%i:%s')
@@ -887,11 +848,7 @@ class utils
// Bulk export actions
$aResult[] = new JSPopupMenuItem('UI:Menu:CSVExport', Dict::S('UI:Menu:CSVExport'), "ExportListDlg('$sOQL', '$sDataTableId', 'csv', ".json_encode(Dict::S('UI:Menu:CSVExport')).")");
$aResult[] = new JSPopupMenuItem('UI:Menu:ExportXLSX', Dict::S('ExcelExporter:ExportMenu'), "ExportListDlg('$sOQL', '$sDataTableId', 'xlsx', ".json_encode(Dict::S('ExcelExporter:ExportMenu')).")");
if (extension_loaded('gd'))
{
// PDF export requires GD
$aResult[] = new JSPopupMenuItem('UI:Menu:ExportPDF', Dict::S('UI:Menu:ExportPDF'), "ExportListDlg('$sOQL', '$sDataTableId', 'pdf', ".json_encode(Dict::S('UI:Menu:ExportPDF')).")");
}
$aResult[] = new JSPopupMenuItem('UI:Menu:ExportPDF', Dict::S('UI:Menu:ExportPDF'), "ExportListDlg('$sOQL', '$sDataTableId', 'pdf', ".json_encode(Dict::S('UI:Menu:ExportPDF')).")");
}
$aResult[] = new JSPopupMenuItem('UI:Menu:AddToDashboard', Dict::S('UI:Menu:AddToDashboard'), "DashletCreationDlg('$sOQL')");
$aResult[] = new JSPopupMenuItem('UI:Menu:ShortcutList', Dict::S('UI:Menu:ShortcutList'), "ShortcutListDlg('$sOQL', '$sDataTableId', '$sContext')");
@@ -1318,21 +1275,10 @@ class utils
*/
public static function ResizeImageToFit(ormDocument $oImage, $iWidth, $iHeight, $iMaxImageWidth, $iMaxImageHeight)
{
// If image size smaller than maximums, we do nothing
if (($iWidth <= $iMaxImageWidth) && ($iHeight <= $iMaxImageHeight))
{
return $oImage;
}
// If gd extension is not loaded, we put a warning in the log and return the image as is
if (extension_loaded('gd') === false)
{
IssueLog::Warning('Image could not be resized as the "gd" extension does not seem to be loaded. It will remain as ' . $iWidth . 'x' . $iHeight . ' instead of ' . $iMaxImageWidth . 'x' . $iMaxImageHeight);
return $oImage;
}
switch($oImage->GetMimeType())
{
case 'image/gif':

View File

@@ -138,22 +138,6 @@ class WizardHelper
$oObj->Set($sAttCode, $value);
}
}
else if ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime
{
if ($value != null)
{
$oDate = $oAttDef->GetFormat()->Parse($value);
if ($oDate instanceof DateTime)
{
$value = $oDate->format($oAttDef->GetInternalFormat());
}
else
{
$value = null;
}
}
$oObj->Set($sAttCode, $value);
}
else
{
$oObj->Set($sAttCode, $value);

View File

@@ -1,69 +0,0 @@
<?php
// Copyright (C) 2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
// Emulate the API of APC, over APCU
// Note: for PHP < 7, this compatibility used to be provided by APCU itself (if compiled with some options)
// for PHP 7+, it can be provided by the mean of apcu_bc, which is not so simple to install
// The current emulation aims at skipping this complexity
if (!function_exists('apc_store') && function_exists('apcu_store'))
{
function apc_add($key, $var, $ttl = 0)
{
return apcu_add($key, $var, $ttl);
}
function apc_cache_info($cache_type = '', $limited = false)
{
return apcu_cache_info($limited);
}
function apc_cas($key, $old, $new)
{
return apcu_cas($key, $old, $new);
}
function apc_clear_cache($cache_type = '')
{
return apcu_clear_cache();
}
function apc_dec($key, $step = 1, &$success = null)
{
apcu_dec($key, $step, $success);
}
function apc_delete($key)
{
return apcu_delete($key);
}
function apc_exists($keys)
{
return apcu_exists($keys);
}
function apc_fetch($key)
{
return apcu_fetch($key);
}
function apc_inc($key, $step = 1, &$success = null)
{
apcu_inc($key, $step, $success);
}
function apc_sma_info($limited = false)
{
return apcu_sma_info($limited);
}
function apc_store($key, $var, $ttl = 0)
{
return apcu_store($key, $var, $ttl);
}
}

View File

@@ -2116,41 +2116,6 @@ class AttributeFinalClass extends AttributeString
}
}
/**
* An enum can be localized
*/
public function MakeValueFromString($sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null, $sAttributeQualifier = null)
{
if ($bLocalizedValue)
{
// Lookup for the value matching the input
//
$sFoundValue = null;
$aRawValues = self::GetAllowedValues();
if (!is_null($aRawValues))
{
foreach ($aRawValues as $sKey => $sValue)
{
if ($sProposedValue == $sValue)
{
$sFoundValue = $sKey;
break;
}
}
}
if (is_null($sFoundValue))
{
return null;
}
return $this->MakeRealValue($sFoundValue, null);
}
else
{
return parent::MakeValueFromString($sProposedValue, $bLocalizedValue, $sSepItem, $sSepAttribute, $sSepValue, $sAttributeQualifier);
}
}
// Because this is sometimes used to get a localized/string version of an attribute...
public function GetEditValue($sValue, $oHostObj = null)
{
@@ -3811,17 +3776,6 @@ class AttributeDateTime extends AttributeDBField
}
if (!is_numeric($proposedValue))
{
// Check the format
try
{
$oFormat = new DateTimeFormat($this->GetInternalFormat());
$oTrash = $oFormat->Parse($proposedValue);
}
catch (Exception $e)
{
throw new Exception('Wrong format for date attribute '.$this->GetCode().', expecting "'.$this->GetInternalFormat().'" and got "'.$proposedValue.'"');
}
return $proposedValue;
}
@@ -4049,7 +4003,7 @@ class AttributeDuration extends AttributeInteger
static public function GetFormFieldClass()
{
return '\\Combodo\\iTop\\Form\\Field\\DurationField';
return '\\Combodo\\iTop\\Form\\Field\\LabelField';
}
public function MakeFormField(DBObject $oObject, $oFormField = null)
@@ -4063,7 +4017,7 @@ class AttributeDuration extends AttributeInteger
// Note : As of today, this attribute is -by nature- only supported in readonly mode, not edition
$sAttCode = $this->GetCode();
$oFormField->SetCurrentValue($oObject->Get($sAttCode));
$oFormField->SetCurrentValue(html_entity_decode($oObject->GetAsHTML($sAttCode), ENT_QUOTES, 'UTF-8'));
$oFormField->SetReadOnly(true);
return $oFormField;
@@ -4376,13 +4330,9 @@ class AttributeExternalKey extends AttributeDBFieldVoid
$oTmpField = $oFormField;
$oFormField->SetOnFinalizeCallback(function() use ($oTmpField, $oTmpAttDef, $oObject)
{
// We set search object only if it has not already been set (overrided)
if ($oTmpField->GetSearch() === null)
{
$oSearch = DBSearch::FromOQL($oTmpAttDef->GetValuesDef()->GetFilterExpression());
$oSearch->SetInternalParams(array('this' => $oObject));
$oTmpField->SetSearch($oSearch);
}
$oSearch = DBSearch::FromOQL($oTmpAttDef->GetValuesDef()->GetFilterExpression());
$oSearch->SetInternalParams(array('this' => $oObject));
$oTmpField->SetSearch($oSearch);
});
}
else
@@ -5113,33 +5063,6 @@ class AttributeBlob extends AttributeDefinition
}
return $sFingerprint;
}
static public function GetFormFieldClass()
{
return '\\Combodo\\iTop\\Form\\Field\\BlobField';
}
public function MakeFormField(DBObject $oObject, $oFormField = null)
{
if ($oFormField === null)
{
$sFormFieldClass = static::GetFormFieldClass();
$oFormField = new $sFormFieldClass($this->GetCode());
}
// Note: As of today we want this field to always be read-only
$oFormField->SetReadOnly(true);
// Generating urls
$value = $oObject->Get($this->GetCode());
$oFormField->SetDownloadUrl($value->GetDownloadURL(get_class($oObject), $oObject->GetKey(), $this->GetCode()));
$oFormField->SetDisplayUrl($value->GetDisplayURL(get_class($oObject), $oObject->GetKey(), $this->GetCode()));
parent::MakeFormField($oObject, $oFormField);
return $oFormField;
}
}
/**

View File

@@ -22,7 +22,6 @@ MetaModel::IncludeModule('application/user.preferences.class.inc.php');
MetaModel::IncludeModule('application/user.dashboard.class.inc.php');
MetaModel::IncludeModule('application/audit.rule.class.inc.php');
MetaModel::IncludeModule('application/query.class.inc.php');
MetaModel::IncludeModule('setup/moduleinstallation.class.inc.php');
MetaModel::IncludeModule('core/event.class.inc.php');
MetaModel::IncludeModule('core/action.class.inc.php');

View File

@@ -828,8 +828,8 @@ class BulkChange
$sFormat = $sDateFormat;
}
$oFormat = new DateTimeFormat($sFormat);
$sRegExp = $oFormat->ToRegExpr('/');
if (!preg_match($sRegExp, $this->m_aData[$iRow][$iCol]))
$sRegExp = $oFormat->ToRegExpr();
if (!preg_match('/'.$sRegExp.'/', $this->m_aData[$iRow][$iCol]))
{
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
}

View File

@@ -412,11 +412,7 @@ abstract class BulkExport
// The built-in exports
require_once(APPROOT.'core/tabularbulkexport.class.inc.php');
require_once(APPROOT.'core/htmlbulkexport.class.inc.php');
if (extension_loaded('gd'))
{
// PDF export - via TCPDF - requires GD
require_once(APPROOT.'core/pdfbulkexport.class.inc.php');
}
require_once(APPROOT.'core/pdfbulkexport.class.inc.php');
require_once(APPROOT.'core/csvbulkexport.class.inc.php');
require_once(APPROOT.'core/excelbulkexport.class.inc.php');
require_once(APPROOT.'core/spreadsheetbulkexport.class.inc.php');

View File

@@ -246,7 +246,7 @@ class Config
),
'access_mode' => array(
'type' => 'integer',
'description' => 'Access mode: ACCESS_READONLY = 0, ACCESS_ADMIN_WRITE = 2, ACCESS_FULL = 3',
'description' => 'Combination of flags (ACCESS_USER_WRITE | ACCESS_ADMIN_WRITE, or ACCESS_FULL)',
'default' => ACCESS_FULL,
'value' => ACCESS_FULL,
'source_of_value' => '',

View File

@@ -413,16 +413,10 @@ EOF
/**
* Get the regular expression to (approximately) validate a date/time for the current format
* The validation does not take into account the number of days in a month (i.e. June 31st will pass, as well as Feb 30th!)
* @param string $sDelimiter Surround the regexp (and escape) if needed
* @return string The regular expression in PCRE syntax
*/
public function ToRegExpr($sDelimiter = null)
public function ToRegExpr()
{
$sRet = '^'.$this->Transform('regexpr', "\\%s", false /* escape all */, '.?*$^()[]:').'$';
if ($sDelimiter !== null)
{
$sRet = $sDelimiter.str_replace($sDelimiter, '\\'.$sDelimiter, $sRet).$sDelimiter;
}
return $sRet;
return '^'.$this->Transform('regexpr', "\\%s", false /* escape all */, '.?*$^()[]/:').'$';
}
}

View File

@@ -192,14 +192,10 @@ abstract class DBObject implements iDisplay
return true;
}
/**
* @param bool $bAllowAllData DEPRECATED: the reload must never fail!
* @throws CoreException
*/
public function Reload($bAllowAllData = false)
{
assert($this->m_bIsInDB);
$aRow = MetaModel::MakeSingleRow(get_class($this), $this->m_iKey, false /* must be found */, true /* AllowAllData */);
$aRow = MetaModel::MakeSingleRow(get_class($this), $this->m_iKey, false /* must be found */, $bAllowAllData/* in the future $this->m_bAllowAllData ??*/);
if (empty($aRow))
{
throw new CoreException("Failed to reload object of class '".get_class($this)."', id = ".$this->m_iKey);
@@ -1935,7 +1931,6 @@ abstract class DBObject implements iDisplay
{
$oFilter = new DBObjectSearch(get_class($this));
$oFilter->AddCondition('id', $this->m_iKey, '=');
$oFilter->AllowAllData();
$sSQL = $oFilter->MakeUpdateQuery($aDBChanges);
CMDBSource::Query($sSQL);

View File

@@ -23,9 +23,7 @@
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
// Dev hack for disabling the some query build optimizations (Folding/Merging)
define('ENABLE_OPT', true);
class DBObjectSearch extends DBSearch
{
@@ -37,11 +35,6 @@ class DBObjectSearch extends DBSearch
private $m_aPointingTo;
private $m_aReferencedBy;
// By default, some information may be hidden to the current user
// But it may happen that we need to disable that feature
protected $m_bAllowAllData = false;
protected $m_bDataFiltered = false;
public function __construct($sClass, $sClassAlias = null)
{
parent::__construct();
@@ -59,11 +52,6 @@ class DBObjectSearch extends DBSearch
$this->m_aReferencedBy = array();
}
public function AllowAllData($bAllowAllData = true) {$this->m_bAllowAllData = $bAllowAllData;}
public function IsAllDataAllowed() {return $this->m_bAllowAllData;}
protected function IsDataFiltered() {return $this->m_bDataFiltered; }
protected function SetDataFiltered() {$this->m_bDataFiltered = true;}
// Create a search definition that leads to 0 result, still a valid search object
static public function FromEmptySet($sClass)
{
@@ -184,87 +172,12 @@ class DBObjectSearch extends DBSearch
{
if (!array_key_exists($sAlias, $this->m_aClasses))
{
throw new CoreException("SetSelectedClasses: Invalid class alias $sAlias");
throw new CoreException("Invalid class alias $sAlias");
}
$this->m_aSelectedClasses[$sAlias] = $this->m_aClasses[$sAlias];
}
}
/**
* Change any alias of the query tree
*
* @param $sOldName
* @param $sNewName
* @return bool True if the alias has been found and changed
*/
public function RenameAlias($sOldName, $sNewName)
{
$bFound = false;
if (array_key_exists($sOldName, $this->m_aClasses))
{
$bFound = true;
}
if (array_key_exists($sNewName, $this->m_aClasses))
{
throw new Exception("RenameAlias: alias '$sNewName' already used");
}
$aClasses = array();
foreach ($this->m_aClasses as $sAlias => $sClass)
{
if ($sAlias === $sOldName)
{
$aClasses[$sNewName] = $sClass;
}
else
{
$aClasses[$sAlias] = $sClass;
}
}
$this->m_aClasses = $aClasses;
$aSelectedClasses = array();
foreach ($this->m_aSelectedClasses as $sAlias => $sClass)
{
if ($sAlias === $sOldName)
{
$aSelectedClasses[$sNewName] = $sClass;
}
else
{
$aSelectedClasses[$sAlias] = $sClass;
}
}
$this->m_aSelectedClasses = $aSelectedClasses;
$this->m_oSearchCondition->RenameAlias($sOldName, $sNewName);
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
{
foreach($aPointingTo as $iOperatorCode => $aFilter)
{
foreach($aFilter as $oExtFilter)
{
$bFound = $oExtFilter->RenameAlias($sOldName, $sNewName) || $bFound;
}
}
}
foreach($this->m_aReferencedBy as $sForeignClass => $aReferences)
{
foreach($aReferences as $sForeignExtKeyAttCode => $aFiltersByOperator)
{
foreach ($aFiltersByOperator as $iOperatorCode => $aFilters)
{
foreach ($aFilters as $oForeignFilter)
{
$bFound = $oForeignFilter->RenameAlias($sOldName, $sNewName) || $bFound;
}
}
}
}
return $bFound;
}
public function SetModifierProperty($sPluginClass, $sProperty, $value)
{
$this->m_aModifierProperties[$sPluginClass][$sProperty] = $value;
@@ -641,85 +554,8 @@ class DBObjectSearch extends DBSearch
return null;
}
/**
* Helper to
* - convert a translation table (format optimized for the translation in an expression tree) into simple hash
* - compile over an eventually existing map
*
* @param $aRealiasingMap Map to update
* @param $aAliasTranslation Translation table resulting from calls to MergeWith_InNamespace
* @return array of <old-alias> => <new-alias>
*/
protected function UpdateRealiasingMap(&$aRealiasingMap, $aAliasTranslation)
{
if ($aRealiasingMap !== null)
{
foreach ($aAliasTranslation as $sPrevAlias => $aRules)
{
if (isset($aRules['*']))
{
$sNewAlias = $aRules['*'];
$sOriginalAlias = array_search($sPrevAlias, $aRealiasingMap);
if ($sOriginalAlias !== false)
{
$aRealiasingMap[$sOriginalAlias] = $sNewAlias;
}
else
{
$aRealiasingMap[$sPrevAlias] = $sNewAlias;
}
}
}
}
}
/**
* Completes the list of alias=>class by browsing the whole structure recursively
* This a workaround to handle some cases in which the list of classes is not correctly updated.
* This code should disappear as soon as DBObjectSearch get split between a container search class and a Node class
*
* @param $aClasses List to be completed
*/
protected function RecomputeClassList(&$aClasses)
{
$aClasses[$this->GetFirstJoinedClassAlias()] = $this->GetFirstJoinedClass();
// Recurse in the query tree
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
{
foreach($aPointingTo as $iOperatorCode => $aFilter)
{
foreach($aFilter as $oFilter)
{
$oFilter->RecomputeClassList($aClasses);
}
}
}
foreach($this->m_aReferencedBy as $sForeignClass=>$aReferences)
{
foreach($aReferences as $sForeignExtKeyAttCode => $aFiltersByOperator)
{
foreach ($aFiltersByOperator as $iOperatorCode => $aFilters)
{
foreach ($aFilters as $oForeignFilter)
{
$oForeignFilter->RecomputeClassList($aClasses);
}
}
}
}
}
/**
* @param DBObjectSearch $oFilter
* @param $sExtKeyAttCode
* @param int $iOperatorCode
* @param null $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed
* @throws CoreException
* @throws CoreWarning
*/
public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null)
public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS)
{
if (!MetaModel::IsValidKeyAttCode($this->GetClass(), $sExtKeyAttCode))
{
@@ -743,22 +579,6 @@ class DBObjectSearch extends DBSearch
$aAliasTranslation = array();
$res = $this->AddCondition_PointingTo_InNameSpace($oFilter, $sExtKeyAttCode, $this->m_aClasses, $aAliasTranslation, $iOperatorCode);
$this->TransferConditionExpression($oFilter, $aAliasTranslation);
$this->UpdateRealiasingMap($aRealiasingMap, $aAliasTranslation);
if (ENABLE_OPT && ($oFilter->GetClass() == $oFilter->GetFirstJoinedClass()))
{
if (isset($oFilter->m_aReferencedBy[$this->GetClass()][$sExtKeyAttCode][$iOperatorCode]))
{
// Optimization - fold sibling query
$oRemoteFilter = $oFilter->m_aReferencedBy[$this->GetClass()][$sExtKeyAttCode][$iOperatorCode][0];
$aAliasTranslation = array();
$this->MergeWith_InNamespace($oRemoteFilter, $this->m_aClasses, $aAliasTranslation);
unset($oFilter->m_aReferencedBy[$this->GetClass()][$sExtKeyAttCode][$iOperatorCode]);
$this->m_oSearchCondition = $this->m_oSearchCondition->Translate($aAliasTranslation, false, false);
$this->UpdateRealiasingMap($aRealiasingMap, $aAliasTranslation);
}
}
$this->RecomputeClassList($this->m_aClasses);
return $res;
}
@@ -767,25 +587,11 @@ class DBObjectSearch extends DBSearch
// Find the node on which the new tree must be attached (most of the time it is "this")
$oReceivingFilter = $this->GetNode($this->GetClassAlias());
if (ENABLE_OPT && isset($oReceivingFilter->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode]))
{
$oExisting = $oReceivingFilter->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][0];
$oExisting->MergeWith_InNamespace($oFilter, $oExisting->m_aClasses, $aAliasTranslation);
}
else
{
$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation);
$oReceivingFilter->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][] = $oFilter;
}
$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation);
$oReceivingFilter->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][] = $oFilter;
}
/**
* @param DBObjectSearch $oFilter
* @param $sForeignExtKeyAttCode
* @param int $iOperatorCode
* @param null $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed
*/
public function AddCondition_ReferencedBy(DBObjectSearch $oFilter, $sForeignExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null)
public function AddCondition_ReferencedBy(DBObjectSearch $oFilter, $sForeignExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS)
{
$sForeignClass = $oFilter->GetClass();
if (!MetaModel::IsValidKeyAttCode($sForeignClass, $sForeignExtKeyAttCode))
@@ -798,7 +604,6 @@ class DBObjectSearch extends DBSearch
// à refaire en spécifique dans FromOQL
throw new CoreException("The specified filter (objects referencing an object of class {$this->GetClass()}) is not compatible with the key '{$sForeignClass}::$sForeignExtKeyAttCode', which is pointing to {$oAttExtKey->GetTargetClass()}");
}
// Note: though it seems to be a good practice to clone the given source filter
// (as it was done and fixed an issue in Intersect())
// this was not implemented here because it was causing a regression (login as admin, select an org, click on any badge)
@@ -808,22 +613,6 @@ class DBObjectSearch extends DBSearch
$aAliasTranslation = array();
$res = $this->AddCondition_ReferencedBy_InNameSpace($oFilter, $sForeignExtKeyAttCode, $this->m_aClasses, $aAliasTranslation, $iOperatorCode);
$this->TransferConditionExpression($oFilter, $aAliasTranslation);
$this->UpdateRealiasingMap($aRealiasingMap, $aAliasTranslation);
if (ENABLE_OPT && ($oFilter->GetClass() == $oFilter->GetFirstJoinedClass()))
{
if (isset($oFilter->m_aPointingTo[$sForeignExtKeyAttCode][$iOperatorCode]))
{
// Optimization - fold sibling query
$oRemoteFilter = $oFilter->m_aPointingTo[$sForeignExtKeyAttCode][$iOperatorCode][0];
$aAliasTranslation = array();
$this->MergeWith_InNamespace($oRemoteFilter, $this->m_aClasses, $aAliasTranslation);
unset($oFilter->m_aPointingTo[$sForeignExtKeyAttCode][$iOperatorCode]);
$this->m_oSearchCondition = $this->m_oSearchCondition->Translate($aAliasTranslation, false, false);
$this->UpdateRealiasingMap($aRealiasingMap, $aAliasTranslation);
}
}
$this->RecomputeClassList($this->m_aClasses);
return $res;
}
@@ -834,16 +623,8 @@ class DBObjectSearch extends DBSearch
// Find the node on which the new tree must be attached (most of the time it is "this")
$oReceivingFilter = $this->GetNode($this->GetClassAlias());
if (ENABLE_OPT && isset($oReceivingFilter->m_aReferencedBy[$sForeignClass][$sForeignExtKeyAttCode][$iOperatorCode]))
{
$oExisting = $oReceivingFilter->m_aReferencedBy[$sForeignClass][$sForeignExtKeyAttCode][$iOperatorCode][0];
$oExisting->MergeWith_InNamespace($oFilter, $oExisting->m_aClasses, $aAliasTranslation);
}
else
{
$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation);
$oReceivingFilter->m_aReferencedBy[$sForeignClass][$sForeignExtKeyAttCode][$iOperatorCode][] = $oFilter;
}
$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation);
$oReceivingFilter->m_aReferencedBy[$sForeignClass][$sForeignExtKeyAttCode][$iOperatorCode][] = $oFilter;
}
public function Intersect(DBSearch $oFilter)
@@ -873,10 +654,7 @@ class DBObjectSearch extends DBSearch
$oLeftFilter = $this->DeepClone();
$oRightFilter = $oRightFilter->DeepClone();
$bAllowAllData = ($oLeftFilter->IsAllDataAllowed() && $oRightFilter->IsAllDataAllowed());
$oLeftFilter->AllowAllData($bAllowAllData);
if ($oLeftFilter->GetClass() != $oRightFilter->GetClass())
{
if (MetaModel::IsParentClass($oLeftFilter->GetClass(), $oRightFilter->GetClass()))
@@ -1032,7 +810,7 @@ class DBObjectSearch extends DBSearch
return $this->m_oSearchCondition->ApplyParameters(array_merge($this->m_aParams, $aArgs));
}
public function ToOQL($bDevelopParams = false, $aContextParams = null, $bWithAllowAllFlag = false)
public function ToOQL($bDevelopParams = false, $aContextParams = null)
{
// Currently unused, but could be useful later
$bRetrofitParams = false;
@@ -1072,10 +850,6 @@ class DBObjectSearch extends DBSearch
{
$sRes .= " AND MATCHES '$sFullText'";
}
if ($bWithAllowAllFlag && $this->m_bAllowAllData)
{
$sRes .= " ALLOW ALL DATA";
}
return $sRes;
}
@@ -1233,22 +1007,6 @@ class DBObjectSearch extends DBSearch
$aAliases = array($sClassAlias => $sClass);
// Note: the condition must be built here, it may be altered later on when optimizing some joins
$oConditionTree = $oOqlQuery->GetCondition();
if ($oConditionTree instanceof Expression)
{
$aRawAliases = array($sClassAlias => $sClass);
$aJoinSpecs = $oOqlQuery->GetJoins();
if (is_array($aJoinSpecs))
{
foreach ($aJoinSpecs as $oJoinSpec)
{
$aRawAliases[$oJoinSpec->GetClassAlias()] = $oJoinSpec->GetClass();
}
}
$this->m_oSearchCondition = $this->OQLExpressionToCondition($sQuery, $oConditionTree, $aRawAliases);
}
// Maintain an array of filters, because the flat list is in fact referring to a tree
// And this will be an easy way to dispatch the conditions
// $this will be referenced by the other filters, or the other way around...
@@ -1257,32 +1015,19 @@ class DBObjectSearch extends DBSearch
$aJoinSpecs = $oOqlQuery->GetJoins();
if (is_array($aJoinSpecs))
{
$aAliasTranslation = array();
foreach ($aJoinSpecs as $oJoinSpec)
{
$sJoinClass = $oJoinSpec->GetClass();
$sJoinClassAlias = $oJoinSpec->GetClassAlias();
if (isset($aAliasTranslation[$sJoinClassAlias]['*']))
{
$sJoinClassAlias = $aAliasTranslation[$sJoinClassAlias]['*'];
}
// Assumption: ext key on the left only !!!
// normalization should take care of this
$oLeftField = $oJoinSpec->GetLeftField();
$sFromClass = $oLeftField->GetParent();
if (isset($aAliasTranslation[$sFromClass]['*']))
{
$sFromClass = $aAliasTranslation[$sFromClass]['*'];
}
$sExtKeyAttCode = $oLeftField->GetName();
$oRightField = $oJoinSpec->GetRightField();
$sToClass = $oRightField->GetParent();
if (isset($aAliasTranslation[$sToClass]['*']))
{
$sToClass = $aAliasTranslation[$sToClass]['*'];
}
$aAliases[$sJoinClassAlias] = $sJoinClass;
$aJoinItems[$sJoinClassAlias] = new DBObjectSearch($sJoinClass, $sJoinClassAlias);
@@ -1324,16 +1069,19 @@ class DBObjectSearch extends DBSearch
{
$oReceiver = $aJoinItems[$sToClass];
$oNewComer = $aJoinItems[$sFromClass];
$aAliasTranslation = array();
$oReceiver->AddCondition_ReferencedBy_InNameSpace($oNewComer, $sExtKeyAttCode, $oReceiver->m_aClasses, $aAliasTranslation, $iOperatorCode);
}
else
{
$oReceiver = $aJoinItems[$sFromClass];
$oNewComer = $aJoinItems[$sToClass];
$aAliasTranslation = array();
$oReceiver->AddCondition_PointingTo_InNameSpace($oNewComer, $sExtKeyAttCode, $oReceiver->m_aClasses, $aAliasTranslation, $iOperatorCode);
}
}
$this->m_oSearchCondition = $this->m_oSearchCondition->Translate($aAliasTranslation, false, false /* leave unresolved fields */);
}
// Check and prepare the select information
@@ -1344,6 +1092,12 @@ class DBObjectSearch extends DBSearch
$this->m_aSelectedClasses[$sClassToSelect] = $aAliases[$sClassToSelect];
}
$this->m_aClasses = $aAliases;
$oConditionTree = $oOqlQuery->GetCondition();
if ($oConditionTree instanceof Expression)
{
$this->m_oSearchCondition = $this->OQLExpressionToCondition($sQuery, $oConditionTree, $aAliases);
}
}
////////////////////////////////////////////////////////////////////////////
@@ -1375,139 +1129,7 @@ class DBObjectSearch extends DBSearch
return $oSQLQuery->RenderUpdate($aScalarArgs);
}
public function GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr = null, $aSelectedClasses = null)
{
// Hide objects that are not visible to the current user
//
$oSearch = $this;
if (!$this->IsAllDataAllowed() && !$this->IsDataFiltered())
{
$oVisibleObjects = UserRights::GetSelectFilter($this->GetClass(), $this->GetModifierProperties('UserRightsGetSelectFilter'));
if ($oVisibleObjects === false)
{
// Make sure this is a valid search object, saying NO for all
$oVisibleObjects = DBObjectSearch::FromEmptySet($this->GetClass());
}
if (is_object($oVisibleObjects))
{
$oVisibleObjects->AllowAllData();
$oSearch = $this->Intersect($oVisibleObjects);
$oSearch->SetDataFiltered();
}
else
{
// should be true at this point, meaning that no additional filtering
// is required
}
}
// Compute query modifiers properties (can be set in the search itself, by the context, etc.)
//
$aModifierProperties = MetaModel::MakeModifierProperties($oSearch);
// Create a unique cache id
//
if (self::$m_bQueryCacheEnabled || self::$m_bTraceQueries)
{
// Need to identify the query
$sOqlQuery = $oSearch->ToOql(false, null, true);
if (count($aModifierProperties))
{
array_multisort($aModifierProperties);
$sModifierProperties = json_encode($aModifierProperties);
}
else
{
$sModifierProperties = '';
}
$sRawId = $sOqlQuery.$sModifierProperties;
if (!is_null($aAttToLoad))
{
$sRawId .= json_encode($aAttToLoad);
}
if (!is_null($aGroupByExpr))
{
foreach($aGroupByExpr as $sAlias => $oExpr)
{
$sRawId .= 'g:'.$sAlias.'!'.$oExpr->Render();
}
}
$sRawId .= $bGetCount;
if (is_array($aSelectedClasses))
{
$sRawId .= implode(',', $aSelectedClasses); // Unions may alter the list of selected columns
}
$sOqlId = md5($sRawId);
}
else
{
$sOqlQuery = "SELECTING... ".$oSearch->GetClass();
$sOqlId = "query id ? n/a";
}
// Query caching
//
if (self::$m_bQueryCacheEnabled)
{
// Warning: using directly the query string as the key to the hash array can FAIL if the string
// is long and the differences are only near the end... so it's safer (but not bullet proof?)
// to use a hash (like md5) of the string as the key !
//
// Example of two queries that were found as similar by the hash array:
// SELECT SLT JOIN lnkSLTToSLA AS L1 ON L1.slt_id=SLT.id JOIN SLA ON L1.sla_id = SLA.id JOIN lnkContractToSLA AS L2 ON L2.sla_id = SLA.id JOIN CustomerContract ON L2.contract_id = CustomerContract.id WHERE SLT.ticket_priority = 1 AND SLA.service_id = 3 AND SLT.metric = 'TTO' AND CustomerContract.customer_id = 2
// and
// SELECT SLT JOIN lnkSLTToSLA AS L1 ON L1.slt_id=SLT.id JOIN SLA ON L1.sla_id = SLA.id JOIN lnkContractToSLA AS L2 ON L2.sla_id = SLA.id JOIN CustomerContract ON L2.contract_id = CustomerContract.id WHERE SLT.ticket_priority = 1 AND SLA.service_id = 3 AND SLT.metric = 'TTR' AND CustomerContract.customer_id = 2
// the only difference is R instead or O at position 285 (TTR instead of TTO)...
//
if (array_key_exists($sOqlId, self::$m_aQueryStructCache))
{
// hit!
$oSQLQuery = unserialize(serialize(self::$m_aQueryStructCache[$sOqlId]));
// Note: cloning is not enough because the subtree is made of objects
}
elseif (self::$m_bUseAPCCache)
{
// Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter
//
$sOqlAPCCacheId = 'itop-'.MetaModel::GetEnvironmentId().'-query-cache-'.$sOqlId;
$oKPI = new ExecutionKPI();
$result = apc_fetch($sOqlAPCCacheId);
$oKPI->ComputeStats('Query APC (fetch)', $sOqlQuery);
if (is_object($result))
{
$oSQLQuery = $result;
self::$m_aQueryStructCache[$sOqlId] = $oSQLQuery;
}
}
}
if (!isset($oSQLQuery))
{
$oKPI = new ExecutionKPI();
$oSQLQuery = $oSearch->BuildSQLQueryStruct($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr, $aSelectedClasses);
$oKPI->ComputeStats('BuildSQLQueryStruct', $sOqlQuery);
if (self::$m_bQueryCacheEnabled)
{
if (self::$m_bUseAPCCache)
{
$oKPI = new ExecutionKPI();
apc_store($sOqlAPCCacheId, $oSQLQuery, self::$m_iQueryCacheTTL);
$oKPI->ComputeStats('Query APC (store)', $sOqlQuery);
}
self::$m_aQueryStructCache[$sOqlId] = $oSQLQuery->DeepClone();
}
}
return $oSQLQuery;
}
protected function BuildSQLQueryStruct($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr = null, $aSelectedClasses = null)
public function MakeSQLQuery($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr = null, $aSelectedClasses = null)
{
$oBuild = new QueryBuilderContext($this, $aModifierProperties, $aGroupByExpr, $aSelectedClasses);

View File

@@ -445,8 +445,8 @@ class DBObjectSet
/**
* Sets the sort order for loading the rows from the DB. Changing the order by causes a Reload.
*
* @param hash $aOrderBy Format: [alias.]attcode => boolean (true = ascending, false = descending)
*
* @param hash $aOrderBy Format: field_code => boolean (true = ascending, false = descending)
*/
public function SetOrderBy($aOrderBy)
{
@@ -461,34 +461,6 @@ class DBObjectSet
}
}
/**
* Sets the sort order for loading the rows from the DB. Changing the order by causes a Reload.
*
* @param hash $aAliases Format: alias => boolean (true = ascending, false = descending). If omitted, then it defaults to all the selected classes
*/
public function SetOrderByClasses($aAliases = null)
{
if ($aAliases === null)
{
$aAliases = array();
foreach ($this->GetSelectedClasses() as $sAlias => $sClass)
{
$aAliases[$sAlias] = true;
}
}
$aAttributes = array();
foreach ($aAliases as $sAlias => $bClassDirection)
{
foreach (MetaModel::GetOrderByDefault($this->m_oFilter->GetClass($sAlias)) as $sAttCode => $bAttributeDirection)
{
$bDirection = $bClassDirection ? $bAttributeDirection : !$bAttributeDirection;
$aAttributes[$sAlias.'.'.$sAttCode] = $bDirection;
}
}
$this->SetOrderBy($aAttributes);
}
/**
* Returns the 'count' limit for loading the rows from the DB
*

View File

@@ -42,9 +42,14 @@ abstract class DBSearch
const JOIN_POINTING_TO = 0;
const JOIN_REFERENCED_BY = 1;
protected $m_bDataFiltered = false;
protected $m_bNoContextParameters = false;
protected $m_aModifierProperties = array();
// By default, some information may be hidden to the current user
// But it may happen that we need to disable that feature
protected $m_bAllowAllData = false;
public function __construct()
{
}
@@ -57,11 +62,12 @@ abstract class DBSearch
return unserialize(serialize($this)); // Beware this serializes/unserializes the search and its parameters as well
}
abstract public function AllowAllData();
abstract public function IsAllDataAllowed();
public function AllowAllData() {$this->m_bAllowAllData = true;}
public function IsAllDataAllowed() {return $this->m_bAllowAllData;}
public function NoContextParameters() {$this->m_bNoContextParameters = true;}
public function HasContextParameters() {return $this->m_bNoContextParameters;}
public function IsDataFiltered() {return $this->m_bDataFiltered; }
public function SetDataFiltered() {$this->m_bDataFiltered = true;}
public function SetModifierProperty($sPluginClass, $sProperty, $value)
{
@@ -97,15 +103,6 @@ abstract class DBSearch
*/
abstract public function SetSelectedClasses($aSelectedClasses);
/**
* Change any alias of the query tree
*
* @param $sOldName
* @param $sNewName
* @return bool True if the alias has been found and changed
*/
abstract public function RenameAlias($sOldName, $sNewName);
abstract public function IsAny();
public function Describe(){return 'deprecated - use ToOQL() instead';}
@@ -130,35 +127,19 @@ abstract class DBSearch
abstract public function AddConditionAdvanced($sAttSpec, $value);
abstract public function AddCondition_FullText($sFullText);
/**
* @param DBObjectSearch $oFilter
* @param $sExtKeyAttCode
* @param int $iOperatorCode
* @param null $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed
* @throws CoreException
* @throws CoreWarning
*/
abstract public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null);
/**
* @param DBObjectSearch $oFilter
* @param $sForeignExtKeyAttCode
* @param int $iOperatorCode
* @param null $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed
*/
abstract public function AddCondition_ReferencedBy(DBObjectSearch $oFilter, $sForeignExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null);
abstract public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS);
abstract public function AddCondition_ReferencedBy(DBObjectSearch $oFilter, $sForeignExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS);
abstract public function Intersect(DBSearch $oFilter);
/**
*
* @param DBSearch $oFilter
* @param integer $iDirection
* @param string $sExtKeyAttCode
* @param integer $iOperatorCode
* @param array &$RealisasingMap Map of aliases from the attached query, that could have been renamed by the optimization process
* @return DBSearch
*/
public function Join(DBSearch $oFilter, $iDirection, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null)
public function Join(DBSearch $oFilter, $iDirection, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS)
{
$oSourceFilter = $this->DeepClone();
$oRet = null;
@@ -168,7 +149,7 @@ abstract class DBSearch
$aSearches = array();
foreach ($oFilter->GetSearches() as $oSearch)
{
$aSearches[] = $oSourceFilter->Join($oSearch, $iDirection, $sExtKeyAttCode, $iOperatorCode, $aRealiasingMap);
$aSearches[] = $oSourceFilter->Join($oSearch, $iDirection, $sExtKeyAttCode, $iOperatorCode);
}
$oRet = new DBUnionSearch($aSearches);
}
@@ -176,7 +157,7 @@ abstract class DBSearch
{
if ($iDirection === static::JOIN_POINTING_TO)
{
$oSourceFilter->AddCondition_PointingTo($oFilter, $sExtKeyAttCode, $iOperatorCode, $aRealiasingMap);
$oSourceFilter->AddCondition_PointingTo($oFilter, $sExtKeyAttCode, $iOperatorCode);
}
else
{
@@ -184,7 +165,7 @@ abstract class DBSearch
{
throw new Exception('Only TREE_OPERATOR_EQUALS operator code is supported yet for AddCondition_ReferencedBy.');
}
$oSourceFilter->AddCondition_ReferencedBy($oFilter, $sExtKeyAttCode, TREE_OPERATOR_EQUALS, $aRealiasingMap);
$oSourceFilter->AddCondition_ReferencedBy($oFilter, $sExtKeyAttCode);
}
$oRet = $oSourceFilter;
}
@@ -238,7 +219,7 @@ abstract class DBSearch
return $oSearchWithAlias;
}
abstract public function ToOQL($bDevelopParams = false, $aContextParams = null, $bWithAllowAllFlag = false);
abstract public function ToOQL($bDevelopParams = false, $aContextParams = null);
static protected $m_aOQLQueries = array();
@@ -511,8 +492,129 @@ abstract class DBSearch
protected function GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr = null)
{
$oSQLQuery = $this->GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr);
$oSQLQuery->SetSourceOQL($this->ToOQL());
// Hide objects that are not visible to the current user
//
$oSearch = $this;
if (!$this->IsAllDataAllowed() && !$this->IsDataFiltered())
{
$oVisibleObjects = UserRights::GetSelectFilter($this->GetClass(), $this->GetModifierProperties('UserRightsGetSelectFilter'));
if ($oVisibleObjects === false)
{
// Make sure this is a valid search object, saying NO for all
$oVisibleObjects = DBObjectSearch::FromEmptySet($this->GetClass());
}
if (is_object($oVisibleObjects))
{
$oSearch = $this->Intersect($oVisibleObjects);
$oSearch->SetDataFiltered();
}
else
{
// should be true at this point, meaning that no additional filtering
// is required
}
}
// Compute query modifiers properties (can be set in the search itself, by the context, etc.)
//
$aModifierProperties = MetaModel::MakeModifierProperties($oSearch);
// Create a unique cache id
//
if (self::$m_bQueryCacheEnabled || self::$m_bTraceQueries)
{
// Need to identify the query
$sOqlQuery = $oSearch->ToOql();
if (count($aModifierProperties))
{
array_multisort($aModifierProperties);
$sModifierProperties = json_encode($aModifierProperties);
}
else
{
$sModifierProperties = '';
}
$sRawId = $sOqlQuery.$sModifierProperties;
if (!is_null($aAttToLoad))
{
$sRawId .= json_encode($aAttToLoad);
}
if (!is_null($aGroupByExpr))
{
foreach($aGroupByExpr as $sAlias => $oExpr)
{
$sRawId .= 'g:'.$sAlias.'!'.$oExpr->Render();
}
}
$sRawId .= $bGetCount;
$sOqlId = md5($sRawId);
}
else
{
$sOqlQuery = "SELECTING... ".$oSearch->GetClass();
$sOqlId = "query id ? n/a";
}
// Query caching
//
if (self::$m_bQueryCacheEnabled)
{
// Warning: using directly the query string as the key to the hash array can FAIL if the string
// is long and the differences are only near the end... so it's safer (but not bullet proof?)
// to use a hash (like md5) of the string as the key !
//
// Example of two queries that were found as similar by the hash array:
// SELECT SLT JOIN lnkSLTToSLA AS L1 ON L1.slt_id=SLT.id JOIN SLA ON L1.sla_id = SLA.id JOIN lnkContractToSLA AS L2 ON L2.sla_id = SLA.id JOIN CustomerContract ON L2.contract_id = CustomerContract.id WHERE SLT.ticket_priority = 1 AND SLA.service_id = 3 AND SLT.metric = 'TTO' AND CustomerContract.customer_id = 2
// and
// SELECT SLT JOIN lnkSLTToSLA AS L1 ON L1.slt_id=SLT.id JOIN SLA ON L1.sla_id = SLA.id JOIN lnkContractToSLA AS L2 ON L2.sla_id = SLA.id JOIN CustomerContract ON L2.contract_id = CustomerContract.id WHERE SLT.ticket_priority = 1 AND SLA.service_id = 3 AND SLT.metric = 'TTR' AND CustomerContract.customer_id = 2
// the only difference is R instead or O at position 285 (TTR instead of TTO)...
//
if (array_key_exists($sOqlId, self::$m_aQueryStructCache))
{
// hit!
$oSQLQuery = unserialize(serialize(self::$m_aQueryStructCache[$sOqlId]));
// Note: cloning is not enough because the subtree is made of objects
}
elseif (self::$m_bUseAPCCache)
{
// Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter
//
$sOqlAPCCacheId = 'itop-'.MetaModel::GetEnvironmentId().'-query-cache-'.$sOqlId;
$oKPI = new ExecutionKPI();
$result = apc_fetch($sOqlAPCCacheId);
$oKPI->ComputeStats('Query APC (fetch)', $sOqlQuery);
if (is_object($result))
{
$oSQLQuery = $result;
self::$m_aQueryStructCache[$sOqlId] = $oSQLQuery;
}
}
}
if (!isset($oSQLQuery))
{
$oKPI = new ExecutionKPI();
$oSQLQuery = $oSearch->MakeSQLQuery($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr);
$oSQLQuery->SetSourceOQL($sOqlQuery);
$oKPI->ComputeStats('MakeSQLQuery', $sOqlQuery);
if (self::$m_bQueryCacheEnabled)
{
if (self::$m_bUseAPCCache)
{
$oKPI = new ExecutionKPI();
apc_store($sOqlAPCCacheId, $oSQLQuery, self::$m_iQueryCacheTTL);
$oKPI->ComputeStats('Query APC (store)', $sOqlQuery);
}
self::$m_aQueryStructCache[$sOqlId] = $oSQLQuery->DeepClone();
}
}
// Join to an additional table, if required...
//
@@ -522,7 +624,7 @@ abstract class DBSearch
$aExtendedFields = array();
foreach($aExtendedDataSpec['fields'] as $sColumn)
{
$sColRef = $this->GetClassAlias().'_extdata_'.$sColumn;
$sColRef = $oSearch->GetClassAlias().'_extdata_'.$sColumn;
$aExtendedFields[$sColRef] = new FieldExpressionResolved($sColumn, $sTableAlias);
}
$oSQLQueryExt = new SQLObjectQuery($aExtendedDataSpec['table'], $sTableAlias, $aExtendedFields);

View File

@@ -55,22 +55,6 @@ class DBUnionSearch extends DBSearch
$this->ComputeSelectedClasses();
}
public function AllowAllData()
{
foreach ($this->aSearches as $oSearch)
{
$oSearch->AllowAllData();
}
}
public function IsAllDataAllowed()
{
foreach ($this->aSearches as $oSearch)
{
if ($oSearch->IsAllDataAllowed() === false) return false;
}
return true;
}
/**
* Find the lowest common ancestor for each of the selected class
*/
@@ -203,23 +187,6 @@ class DBUnionSearch extends DBSearch
$this->ComputeSelectedClasses();
}
/**
* Change any alias of the query tree
*
* @param $sOldName
* @param $sNewName
* @return bool True if the alias has been found and changed
*/
public function RenameAlias($sOldName, $sNewName)
{
$bRet = false;
foreach ($this->aSearches as $oSearch)
{
$bRet = $oSearch->RenameAlias($sOldName, $sNewName) || $bRet;
}
return $bRet;
}
public function IsAny()
{
$bIsAny = true;
@@ -315,33 +282,19 @@ class DBUnionSearch extends DBSearch
}
}
/**
* @param DBObjectSearch $oFilter
* @param $sExtKeyAttCode
* @param int $iOperatorCode
* @param null $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed
* @throws CoreException
* @throws CoreWarning
*/
public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null)
public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS)
{
foreach ($this->aSearches as $oSearch)
{
$oSearch->AddCondition_PointingTo($oFilter, $sExtKeyAttCode, $iOperatorCode, $aRealiasingMap);
$oSearch->AddCondition_PointingTo($oFilter, $sExtKeyAttCode, $iOperatorCode);
}
}
/**
* @param DBObjectSearch $oFilter
* @param $sForeignExtKeyAttCode
* @param int $iOperatorCode
* @param null $aRealiasingMap array of <old-alias> => <new-alias>, for each alias that has changed
*/
public function AddCondition_ReferencedBy(DBObjectSearch $oFilter, $sForeignExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null)
public function AddCondition_ReferencedBy(DBObjectSearch $oFilter, $sForeignExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS)
{
foreach ($this->aSearches as $oSearch)
{
$oSearch->AddCondition_ReferencedBy($oFilter, $sForeignExtKeyAttCode, $iOperatorCode, $aRealiasingMap);
$oSearch->AddCondition_ReferencedBy($oFilter, $sForeignExtKeyAttCode, $iOperatorCode);
}
}
@@ -404,12 +357,12 @@ class DBUnionSearch extends DBSearch
/**
* Overloads for query building
*/
public function ToOQL($bDevelopParams = false, $aContextParams = null, $bWithAllowAllFlag = false)
public function ToOQL($bDevelopParams = false, $aContextParams = null)
{
$aSubQueries = array();
foreach ($this->aSearches as $oSearch)
{
$aSubQueries[] = $oSearch->ToOQL($bDevelopParams, $aContextParams, $bWithAllowAllFlag);
$aSubQueries[] = $oSearch->ToOQL($bDevelopParams, $aContextParams);
}
$sRet = implode(' UNION ', $aSubQueries);
return $sRet;
@@ -456,11 +409,11 @@ class DBUnionSearch extends DBSearch
throw new Exception('MakeUpdateQuery is not implemented for the unions!');
}
protected function GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr = null, $aSelectedClasses = null)
protected function MakeSQLQuery($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr = null, $aSelectedClasses = null)
{
if (count($this->aSearches) == 1)
{
return $this->aSearches[0]->GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr);
return $this->aSearches[0]->MakeSQLQuery($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr);
}
$aSQLQueries = array();
@@ -515,7 +468,7 @@ class DBUnionSearch extends DBSearch
$aQueryGroupByExpr[$sExpressionAlias] = $oExpression->Translate($aTranslationData, false, false);
}
}
$oSubQuery = $oSearch->GetSQLQueryStructure($aQueryAttToLoad, false, $aQueryGroupByExpr, $aSearchSelectedClasses);
$oSubQuery = $oSearch->MakeSQLQuery($aQueryAttToLoad, false, $aModifierProperties, $aQueryGroupByExpr, $aSearchSelectedClasses);
$aSQLQueries[] = $oSubQuery;
}

View File

@@ -195,6 +195,8 @@ class EMail
$aFailedRecipients = array();
$this->m_oMessage->setMaxLineLength(0);
IssueLog::Info(__METHOD__.' '.$this->m_oMessage->getMaxLineLength());
IssueLog::Info(__METHOD__.' '.$this->m_oMessage->toString());
$iSent = $oMailer->send($this->m_oMessage, $aFailedRecipients);
if ($iSent === 0)
{

View File

@@ -138,7 +138,7 @@ class HTMLDOMSanitizer extends HTMLSanitizer
protected static $aTagsWhiteList = array(
'html' => array(),
'body' => array(),
'a' => array('href', 'name', 'style', 'target'),
'a' => array('href', 'name', 'style'),
'p' => array('style'),
'br' => array(),
'span' => array('style'),
@@ -159,7 +159,7 @@ class HTMLDOMSanitizer extends HTMLSanitizer
'nav' => array('style'),
'section' => array('style'),
'code' => array('style'),
'table' => array('style', 'width', 'summary', 'align', 'border', 'cellpadding', 'cellspacing'),
'table' => array('style', 'width'),
'thead' => array('style'),
'tbody' => array('style'),
'tr' => array('style'),
@@ -183,26 +183,17 @@ class HTMLDOMSanitizer extends HTMLSanitizer
'hr' => array('style'),
'pre' => array(),
'center' => array(),
'caption' => array(),
);
protected static $aAttrsWhiteList = array(
'href' => '/^(http:|https:)/i',
'src' => '/^(http:|https:|data:)/i',
);
protected static $aStylesWhiteList = array(
'background-color', 'color', 'float', 'font', 'font-style', 'font-size', 'font-family', 'padding', 'margin', 'border', 'cellpadding', 'cellspacing', 'bordercolor', 'border-collapse', 'width', 'height', 'text-align',
'background-color', 'color', 'float', 'font', 'font-style', 'font-size', 'font-family', 'padding', 'margin', 'border', 'cellpadding', 'cellspacing', 'bordercolor', 'border-collapse', 'width', 'height',
);
public function __construct()
{
if (!array_key_exists('href', self::$aAttrsWhiteList))
{
$sPattern = '/'.str_replace('/', '\/', utils::GetConfig()->Get('url_validation_pattern')).'/i';
self::$aAttrsWhiteList['href'] = $sPattern;
}
}
public function DoSanitize($sHTML)
{
$this->oDoc = new DOMDocument();

View File

@@ -464,7 +464,7 @@ EOF
oEditor.on( 'instanceReady', function() {
if(!CKEDITOR.env.iOS && $('#'+oEditor.id+'_toolbox .editor_magnifier').length == 0)
{
$('#'+oEditor.id+'_toolbox').append('<span class="editor_magnifier" title="$sToggleFullScreen" style="display:block;width:12px;height:11px;border:1px #A6A6A6 solid;cursor:pointer; background-image:url(\\'$sAppRootUrl/images/full-screen.png\\')">&nbsp;</span>');
$('#'+oEditor.id+'_toolbox').append('<span class="editor_magnifier" title="$sToggleFullScreen" style="display:block;width:12px;height:11px;border:1px #A6A6A6 solid;cursor:pointer; background-image:url($sAppRootUrl/images/full-screen.png)">&nbsp;</span>');
$('#'+oEditor.id+'_toolbox .editor_magnifier').on('click', function() {
oEditor.execCommand('maximize');
if ($(this).closest('.cke_maximized').length != 0)
@@ -473,15 +473,12 @@ EOF
}
});
}
if (oEditor.widgets.registered.uploadimage)
{
oEditor.widgets.registered.uploadimage.onUploaded = function( upload ) {
var oData = JSON.parse(upload.xhr.responseText);
this.replaceWith( '<img src="' + upload.url + '" ' +
'width="' + oData.width + '" ' +
'height="' + oData.height + '">' );
}
}
oEditor.widgets.registered.uploadimage.onUploaded = function( upload ) {
var oData = JSON.parse(upload.xhr.responseText);
this.replaceWith( '<img src="' + upload.url + '" ' +
'width="' + oData.width + '" ' +
'height="' + oData.height + '">' );
}
});
});
EOF

View File

@@ -22,7 +22,6 @@ require_once(APPROOT.'core/querymodifier.class.inc.php');
require_once(APPROOT.'core/metamodelmodifier.inc.php');
require_once(APPROOT.'core/computing.inc.php');
require_once(APPROOT.'core/relationgraph.class.inc.php');
require_once(APPROOT.'core/apc-compat.php');
/**
* Metamodel
@@ -1768,10 +1767,10 @@ abstract class MetaModel
$oFriendlyName = new AttributeExternalField($sFriendlyNameAttCode, array("allowed_values"=>null, "extkey_attcode"=>$sKeyAttCode, "target_attcode"=>$sRemoteAttCode, "depends_on"=>array()));
$oFriendlyName->SetHostClass($sClass);
self::$m_aAttribDefs[$sClass][$sFriendlyNameAttCode] = $oFriendlyName;
self::$m_aAttribOrigins[$sClass][$sFriendlyNameAttCode] = self::$m_aAttribOrigins[$sClass][$sKeyAttCode];
self::$m_aAttribOrigins[$sClass][$sFriendlyNameAttCode] = $sRemoteClass;
$oFriendlyNameFlt = new FilterFromAttribute($oFriendlyName);
self::$m_aFilterDefs[$sClass][$sFriendlyNameAttCode] = $oFriendlyNameFlt;
self::$m_aFilterOrigins[$sClass][$sFriendlyNameAttCode] = self::$m_aFilterOrigins[$sClass][$sKeyAttCode];
self::$m_aFilterOrigins[$sClass][$sFriendlyNameAttCode] = $sRemoteClass;
}
else
{
@@ -1780,10 +1779,10 @@ abstract class MetaModel
$oFriendlyName = new AttributeFriendlyName($sFriendlyNameAttCode, $sAttCode);
$oFriendlyName->SetHostClass($sClass);
self::$m_aAttribDefs[$sClass][$sFriendlyNameAttCode] = $oFriendlyName;
self::$m_aAttribOrigins[$sClass][$sFriendlyNameAttCode] = self::$m_aAttribOrigins[$sClass][$sAttCode];
self::$m_aAttribOrigins[$sClass][$sFriendlyNameAttCode] = $sRemoteClass;
$oFriendlyNameFlt = new FilterFromAttribute($oFriendlyName);
self::$m_aFilterDefs[$sClass][$sFriendlyNameAttCode] = $oFriendlyNameFlt;
self::$m_aFilterOrigins[$sClass][$sFriendlyNameAttCode] = self::$m_aFilterOrigins[$sClass][$sAttCode];
self::$m_aFilterOrigins[$sClass][$sFriendlyNameAttCode] = $sRemoteClass;
if (self::HasChildrenClasses($sRemoteClass))
{
@@ -1798,11 +1797,11 @@ abstract class MetaModel
));
$oClassRecall->SetHostClass($sClass);
self::$m_aAttribDefs[$sClass][$sClassRecallAttCode] = $oClassRecall;
self::$m_aAttribOrigins[$sClass][$sClassRecallAttCode] = self::$m_aAttribOrigins[$sClass][$sAttCode];
self::$m_aAttribOrigins[$sClass][$sClassRecallAttCode] = $sRemoteClass;
$oClassFlt = new FilterFromAttribute($oClassRecall);
self::$m_aFilterDefs[$sClass][$sClassRecallAttCode] = $oClassFlt;
self::$m_aFilterOrigins[$sClass][$sClassRecallAttCode] = self::$m_aFilterOrigins[$sClass][$sAttCode];
self::$m_aFilterOrigins[$sClass][$sClassRecallAttCode] = $sRemoteClass;
// Add it to the ZLists where the external key is present
//foreach(self::$m_aListData[$sClass] as $sListCode => $aAttributes)

View File

@@ -639,12 +639,12 @@ class ormCaseLog {
}
public function GetModifiedEntry($sFormat = 'text')
public function GetModifiedEntry()
{
$sModifiedEntry = '';
if ($this->m_bModified)
{
$sModifiedEntry = $this->GetLatestEntry($sFormat);
$sModifiedEntry = $this->GetLatestEntry();
}
return $sModifiedEntry;
}

View File

@@ -87,7 +87,7 @@ class ormCustomFieldsValue
{
$oAttDef = MetaModel::GetAttributeDef(get_class($this->oHostObject), $this->sAttCode);
$oHandler = $oAttDef->GetHandler($this->GetValues());
return $oHandler->GetForTemplate($this->aCurrentValues, $sVerb, $bLocalize);
return 'template...verb='.$sVerb.' sur "'.json_encode($this->aCurrentValues).'"';
}
/**

View File

@@ -115,29 +115,21 @@ class ormDocument
*/
public function GetDownloadLink($sClass, $Id, $sAttCode)
{
return "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/ajax.document.php?operation=download_document&class=$sClass&id=$Id&field=$sAttCode\">".htmlentities($this->GetFileName(), ENT_QUOTES, 'UTF-8')."</a>\n";
}
/**
* Returns an URL to display a document like an image
* @return string
*/
public function GetDisplayURL($sClass, $Id, $sAttCode)
{
return utils::GetAbsoluteUrlAppRoot() . "pages/ajax.render.php?operation=display_document&class=$sClass&id=$Id&field=$sAttCode";
return "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=download_document&class=$sClass&id=$Id&field=$sAttCode\">".htmlentities($this->GetFileName(), ENT_QUOTES, 'UTF-8')."</a>\n";
}
/**
* Returns an URL to download a document like an image (uses HTTP caching)
* @return string
*/
*/
public function GetDownloadURL($sClass, $Id, $sAttCode)
{
// Compute a signature to reset the cache anytime the data changes (this is acceptable if used only with icon files)
$sSignature = md5($this->GetData());
return utils::GetAbsoluteUrlAppRoot() . "pages/ajax.document.php?operation=download_document&class=$sClass&id=$Id&field=$sAttCode&s=$sSignature&cache=86400";
return utils::GetAbsoluteUrlAppRoot()."pages/ajax.document.php?operation=download_document&class=$sClass&id=$Id&field=$sAttCode&s=$sSignature&cache=86400";
}
public function IsPreviewAvailable()
{
$bRet = false;
@@ -184,7 +176,7 @@ class ormDocument
{
$oPage->TrashUnexpectedOutput();
$oPage->SetContentType($oDocument->GetMimeType());
$oPage->SetContentDisposition($sContentDisposition,$oDocument->GetFileName());
//$oPage->SetContentDisposition($sContentDisposition,$oDocument->GetFileName());
$oPage->add($oDocument->GetData());
}
}

View File

@@ -494,7 +494,6 @@ class CheckStopWatchThresholds implements iBackgroundProcess
$sExpression = "SELECT $sClass WHERE {$sAttCode}_laststart AND {$sAttCode}_{$iThreshold}_triggered = 0 AND {$sAttCode}_{$iThreshold}_deadline < '$sNow'";
$oFilter = DBObjectSearch::FromOQL($sExpression);
$oSet = new DBObjectSet($oFilter);
$oSet->OptimizeColumnLoad(array($sAttCode));
while ((time() < $iTimeLimit) && ($oObj = $oSet->Fetch()))
{
$sClass = get_class($oObj);

View File

@@ -1045,12 +1045,7 @@ class UserRights
{
$oUser = self::$m_oUser;
}
if ($oUser === null)
{
// Not logged in: no profile at all
$aProfiles = array();
}
elseif ((self::$m_oUser !== null) && ($oUser->GetKey() == self::$m_oUser->GetKey()))
if ($oUser->GetKey() == self::$m_oUser->GetKey())
{
// Data about the current user can be found into the session data
if (array_key_exists('profile_list', $_SESSION))

View File

@@ -2,19 +2,42 @@
/**
* Локализация интерфейса Combodo iTop подготовлена сообществом iTop по-русски http://community.itop-itsm.ru.
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @license http://opensource.org/licenses/AGPL-3.0
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @link http://community.itop-itsm.ru iTop Russian Community
* @link https://github.com/itop-itsm-ru/itop-rus
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*
* Инструкция по установке
*
* Процесс установки заключается в замене имеющихся локализационных файлов полученными и последующем запуске процедуры обновления iTop для перекомпиляции кода.
* 1. Скопируйте с заменой два полученных файла из "itop-rus/dictionaries" в "путь/до/вашего/itop/dictionaries".
* 2. Скопируйте с заменой полученные файлы "itop-rus/datamodels/2.x/название-модуля/ru.dict.название-модуля.php" в "путь/до/вашего/itop/datamodels/2.x/название-модуля".
* 3. Перейдите по адресу "http://адрес/вашего/itop/setup", при этом файл "путь/до/вашего/itop/conf/production/config-itop.php" должен быть доступен для записи.
* 4. На второй странице установщика выберите "Upgrade an existing iTop instance" и следуйте дальнейшим инструкциям установщика.
*
* Ответы на вопросы по установке и использованию переводов, а также на любые другие вопросы по iTop всегда можно получить на сайте сообщества iTop по-русски http://community.itop-itsm.ru.
*
*/
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: UserExternal
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:UserExternal' => 'Внешний пользователь',
'Class:UserExternal+' => 'Пользователь, аутентифицируемый вне iTop',
'Class:UserExternal+' => 'Пользователь, аутентифицированный вне iTop',
));
?>

View File

@@ -2,21 +2,44 @@
/**
* Локализация интерфейса Combodo iTop подготовлена сообществом iTop по-русски http://community.itop-itsm.ru.
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @license http://opensource.org/licenses/AGPL-3.0
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @link http://community.itop-itsm.ru iTop Russian Community
* @link https://github.com/itop-itsm-ru/itop-rus
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*
* Инструкция по установке
*
* Процесс установки заключается в замене имеющихся локализационных файлов полученными и последующем запуске процедуры обновления iTop для перекомпиляции кода.
* 1. Скопируйте с заменой два полученных файла из "itop-rus/dictionaries" в "путь/до/вашего/itop/dictionaries".
* 2. Скопируйте с заменой полученные файлы "itop-rus/datamodels/2.x/название-модуля/ru.dict.название-модуля.php" в "путь/до/вашего/itop/datamodels/2.x/название-модуля".
* 3. Перейдите по адресу "http://адрес/вашего/itop/setup", при этом файл "путь/до/вашего/itop/conf/production/config-itop.php" должен быть доступен для записи.
* 4. На второй странице установщика выберите "Upgrade an existing iTop instance" и следуйте дальнейшим инструкциям установщика.
*
* Ответы на вопросы по установке и использованию переводов, а также на любые другие вопросы по iTop всегда можно получить на сайте сообщества iTop по-русски http://community.itop-itsm.ru.
*
*/
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: UserLDAP
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:UserLDAP' => 'Пользователь LDAP',
'Class:UserLDAP+' => 'Пользователь, аутентифицируемый через LDAP',
'Class:UserLDAP+' => 'Пользователь, аутентифицированный в LDAP',
'Class:UserLDAP/Attribute:password' => 'Пароль',
'Class:UserLDAP/Attribute:password+' => 'Строка аутентификации пользователя',
));
));
?>

View File

@@ -2,21 +2,44 @@
/**
* Локализация интерфейса Combodo iTop подготовлена сообществом iTop по-русски http://community.itop-itsm.ru.
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @license http://opensource.org/licenses/AGPL-3.0
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @link http://community.itop-itsm.ru iTop Russian Community
* @link https://github.com/itop-itsm-ru/itop-rus
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*
* Инструкция по установке
*
* Процесс установки заключается в замене имеющихся локализационных файлов полученными и последующем запуске процедуры обновления iTop для перекомпиляции кода.
* 1. Скопируйте с заменой два полученных файла из "itop-rus/dictionaries" в "путь/до/вашего/itop/dictionaries".
* 2. Скопируйте с заменой полученные файлы "itop-rus/datamodels/2.x/название-модуля/ru.dict.название-модуля.php" в "путь/до/вашего/itop/datamodels/2.x/название-модуля".
* 3. Перейдите по адресу "http://адрес/вашего/itop/setup", при этом файл "путь/до/вашего/itop/conf/production/config-itop.php" должен быть доступен для записи.
* 4. На второй странице установщика выберите "Upgrade an existing iTop instance" и следуйте дальнейшим инструкциям установщика.
*
* Ответы на вопросы по установке и использованию переводов, а также на любые другие вопросы по iTop всегда можно получить на сайте сообщества iTop по-русски http://community.itop-itsm.ru.
*
*/
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: UserLocal
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:UserLocal' => 'Пользователь iTop',
'Class:UserLocal+' => 'Пользователь, аутентифицируемый через iTop',
'Class:UserLocal+' => 'Пользователь, аутентифицированный в iTop',
'Class:UserLocal/Attribute:password' => 'Пароль',
'Class:UserLocal/Attribute:password+' => 'Строка аутентификации пользователя',
));
));
?>

View File

@@ -1,27 +0,0 @@
<?php
/**
* Локализация интерфейса Combodo iTop подготовлена сообществом iTop по-русски http://community.itop-itsm.ru.
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @link http://community.itop-itsm.ru iTop Russian Community
* @link https://github.com/itop-itsm-ru/itop-rus
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*
*/
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Attachments:TabTitle_Count' => 'Вложения (%1$d)',
'Attachments:EmptyTabTitle' => 'Вложения',
'Attachments:FieldsetTitle' => 'Вложения',
'Attachments:DeleteBtn' => 'Удалить',
'Attachments:History_File_Added' => 'Вложение %1$s добавлено.',
'Attachments:History_File_Removed' => 'Вложение %1$s удалено.',
'Attachments:AddAttachment' => 'Добавить вложение:',
'Attachments:UploadNotAllowedOnThisSystem' => 'Загрузка файлов НЕ разрешена в этой системе. За подробностями обратитесь к администратору вашего iTop',
'Attachment:Max_Go' => '(Максимальный размер файла: %1$s ГБ)',
'Attachment:Max_Mo' => '(Максимальный размер файла: %1$s МБ)',
'Attachment:Max_Ko' => '(Максимальный размер файла: %1$s кБ)',
'Attachments:NoAttachment' => 'Нет вложений.',
'Attachments:PreviewNotAvailable' => 'Предварительный просмотр не доступен для этого типа вложений.',
));

View File

@@ -244,7 +244,6 @@ class BackupExec implements iScheduledProcess
{
break;
}
$iNextPos = false; // necessary on sundays
}
}

View File

@@ -1,50 +0,0 @@
<?php
/**
* Локализация интерфейса Combodo iTop подготовлена сообществом iTop по-русски http://community.itop-itsm.ru.
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @link http://community.itop-itsm.ru iTop Russian Community
* @link https://github.com/itop-itsm-ru/itop-rus
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*
*/
Dict::Add('RU RU', 'Russian', 'Русский', array(
'bkp-backup-running' => 'Выполняется резервное копирование. Пожалуйста, подождите...',
'bkp-restore-running' => 'Выполняется восстановление из резервной копии. Пожалуйста, подождите...',
'Menu:BackupStatus' => 'Резервное копирование',
'bkp-status-title' => 'Резервное копирование по расписанию',
'bkp-status-checks' => 'Настройки и проверки',
'bkp-mysqldump-ok' => 'Утилита mysqldump найдена: %1$s',
'bkp-mysqldump-notfound' => 'Утилиту mysqldump найти не удалось: %1$s - пожалуйста, убедитесь в том, что она установлена, и путь до директории с бинарными файлами добавлен в PATH, либо измените параметр mysql_bindir в файле конфигурации.',
'bkp-mysqldump-issue' => 'Утилита mysqldump на может быть запущена (retcode=%1$d) Пожалуйста, убедитесь в том, что она установлена, и путь до директории с бинарными файлами добавлен в PATH, либо измените параметр mysql_bindir в файле конфигурации.',
'bkp-missing-dir' => 'The target directory %1$s count not be found',
'bkp-free-disk-space' => '<b>%1$s свободно</b> в %2$s',
'bkp-dir-not-writeable' => '%1$s недоступен для записи',
'bkp-wrong-format-spec' => 'Неправильный формат шаблона названия файлов резервных копий (%1$s). Будет использован шаблон по умолчанию: %2$s',
'bkp-name-sample' => 'Название файлов резервных копий зависит от идентификатора БД, даты и времени. Пример: %1$s',
'bkp-week-days' => 'Резервное копирование будет выполняться <b>каждый %1$s в %2$s</b>',
'bkp-retention' => 'Не более <b>%1$d файлов резервных копий будут храниться</b> в целевом каталоге.',
'bkp-next-to-delete' => 'Будет удалена при следующем запуске резервного копирования (см. параметр \"retention_count\")',
'bkp-table-file' => 'Файл',
'bkp-table-file+' => 'Только файлы с расширением .zip считаются файлами резервных копий.',
'bkp-table-size' => 'Размер',
'bkp-table-size+' => '',
'bkp-table-actions' => 'Действия',
'bkp-table-actions+' => '',
'bkp-status-backups-auto' => 'Резервное копирование по расписанию',
'bkp-status-backups-manual' => 'Резервное копирование вручную',
'bkp-status-backups-none' => 'Резервных копий ещё нет',
'bkp-next-backup' => 'Следующее резервное копирование будет выполняться в <b>%1$s</b> (%2$s) в %3$s',
'bkp-button-backup-now' => 'Запустить сейчас!',
'bkp-button-restore-now' => 'Восстановить!',
'bkp-confirm-backup' => 'Пожалуйста, подтвердите, что вы хотите выполнить резервное копирование прямо сейчас.',
'bkp-confirm-restore' => 'Пожалуйста, подтвердите, что вы хотите выполнить восстановление из резервной копии %1$s.',
'bkp-wait-backup' => 'Пожалуйста, дождитесь завершения резервного копирования...',
'bkp-wait-restore' => 'Пожалуйста, дождитесь завершения восстановления...',
'bkp-success-restore' => 'Восстановление успешно завершено.',
));
?>

View File

@@ -2,39 +2,45 @@
/**
* Локализация интерфейса Combodo iTop подготовлена сообществом iTop по-русски http://community.itop-itsm.ru.
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @license http://opensource.org/licenses/AGPL-3.0
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @link http://community.itop-itsm.ru iTop Russian Community
* @link https://github.com/itop-itsm-ru/itop-rus
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*
* Инструкция по установке
*
* Процесс установки заключается в замене имеющихся локализационных файлов полученными и последующем запуске процедуры обновления iTop для перекомпиляции кода.
* 1. Скопируйте с заменой два полученных файла из "itop-rus/dictionaries" в "путь/до/вашего/itop/dictionaries".
* 2. Скопируйте с заменой полученные файлы "itop-rus/datamodels/2.x/название-модуля/ru.dict.название-модуля.php" в "путь/до/вашего/itop/datamodels/2.x/название-модуля".
* 3. Перейдите по адресу "http://адрес/вашего/itop/setup", при этом файл "путь/до/вашего/itop/conf/production/config-itop.php" должен быть доступен для записи.
* 4. На второй странице установщика выберите "Upgrade an existing iTop instance" и следуйте дальнейшим инструкциям установщика.
*
* Ответы на вопросы по установке и использованию переводов, а также на любые другие вопросы по iTop всегда можно получить на сайте сообщества iTop по-русски http://community.itop-itsm.ru.
*
*/
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Menu:ChangeManagement' => 'Управление изменениями',
'Menu:Change:Overview' => 'Обзор',
'Menu:Change:Overview+' => 'Управление изменениями - Обзор',
'Menu:Change:Overview+' => '',
'Menu:NewChange' => 'Новый запрос на изменение',
'Menu:NewChange+' => 'Создание нового запроса на изменение',
'Menu:SearchChanges' => 'Поиск изменений',
'Menu:SearchChanges+' => 'Поиск запросов на изменение',
'Menu:Change:Shortcuts' => 'Ярлыки',
'Menu:Change:Shortcuts+' => 'Ярлыки',
'Menu:WaitingAcceptance' => 'Ожидающие принятия',
'Menu:WaitingAcceptance+' => 'Изменения, ожидающие принятия',
'Menu:WaitingApproval' => 'Ожидающие утверждения',
'Menu:WaitingApproval+' => 'Изменения, ожидающие утверждения',
'Menu:Changes' => 'Открытые',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Изменения, ожидающие принятия',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Изменения, ожидающие утверждения',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Открытые изменения',
'Menu:Changes+' => 'Все открытые изменения',
'Menu:MyChanges' => 'Назначенные мне',
'Menu:MyChanges+' => 'Изменения, назначенные мне',
'Menu:MyChanges' => 'Изменения, назначенные на меня',
'Menu:MyChanges+' => 'Изменения, назначенные на меня (как агента)',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Изменения по категориям за 7 дней',
'UI-ChangeManagementOverview-Last-7-days' => 'Количество изменений за 7 дней',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Изменения по домену за 7 дней',
'UI-ChangeManagementOverview-ChangeByStatus-last-7-days' => 'Изменения по статусу за 7 дней',
'Tickets:Related:OpenChanges' => 'Открытые изменения',
'Tickets:Related:RecentChanges' => 'Недавние изменения (72ч)',
));
// Dictionnay conventions
@@ -83,7 +89,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Change/Attribute:requestor_id+' => '',
'Class:Change/Attribute:requestor_email' => 'Email инициатора запроса',
'Class:Change/Attribute:requestor_email+' => '',
'Class:Change/Attribute:creation_date' => 'Дата создания',
'Class:Change/Attribute:creation_date' => 'Создан',
'Class:Change/Attribute:creation_date+' => '',
'Class:Change/Attribute:impact' => 'Критичность',
'Class:Change/Attribute:impact+' => '',
@@ -113,7 +119,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Change/Attribute:fallback+' => '',
'Class:Change/Attribute:parent_id' => 'Родительское изменение',
'Class:Change/Attribute:parent_id+' => '',
'Class:Change/Attribute:parent_name' => 'Родительское изменение',
'Class:Change/Attribute:parent_name' => 'Имя родительского изменения',
'Class:Change/Attribute:parent_name+' => '',
'Class:Change/Attribute:related_request_list' => 'Связанные запросы',
'Class:Change/Attribute:related_request_list+' => 'Связанные запросы',
@@ -191,7 +197,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:ApprovedChange+' => '',
'Class:ApprovedChange/Attribute:approval_date' => 'Дата утверждения',
'Class:ApprovedChange/Attribute:approval_date+' => '',
'Class:ApprovedChange/Attribute:approval_comment' => 'Комментарий утверждения',
'Class:ApprovedChange/Attribute:approval_comment' => 'Коментарий утверждения',
'Class:ApprovedChange/Attribute:approval_comment+' => '',
'Class:ApprovedChange/Stimulus:ev_validate' => 'Подтвердить',
'Class:ApprovedChange/Stimulus:ev_validate+' => '',
@@ -207,7 +213,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:ApprovedChange/Stimulus:ev_approve+' => '',
'Class:ApprovedChange/Stimulus:ev_replan' => 'Перепланировать',
'Class:ApprovedChange/Stimulus:ev_replan+' => '',
'Class:ApprovedChange/Stimulus:ev_notapprove' => 'Отклонить',
'Class:ApprovedChange/Stimulus:ev_notapprove' => 'Отклонить утверждение',
'Class:ApprovedChange/Stimulus:ev_notapprove+' => '',
'Class:ApprovedChange/Stimulus:ev_implement' => 'Реализовать',
'Class:ApprovedChange/Stimulus:ev_implement+' => '',
@@ -281,4 +287,8 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:EmergencyChange/Stimulus:ev_monitor+' => '',
'Class:EmergencyChange/Stimulus:ev_finish' => 'Закончить',
'Class:EmergencyChange/Stimulus:ev_finish+' => '',
));
'Tickets:Related:OpenChanges' => 'Open changes~~',
'Tickets:Related:RecentChanges' => 'Recent changes (72h)~~',
));
?>

View File

@@ -1,127 +0,0 @@
<?php
/**
* Локализация интерфейса Combodo iTop подготовлена сообществом iTop по-русски http://community.itop-itsm.ru.
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @link http://community.itop-itsm.ru iTop Russian Community
* @link https://github.com/itop-itsm-ru/itop-rus
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*
*/
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Menu:ChangeManagement' => 'Управление изменениями',
'Menu:Change:Overview' => 'Обзор',
'Menu:Change:Overview+' => 'Управление изменениями - Обзор',
'Menu:NewChange' => 'Новый запрос на изменение',
'Menu:NewChange+' => 'Создание нового запроса на изменение',
'Menu:SearchChanges' => 'Поиск изменений',
'Menu:SearchChanges+' => 'Поиск запросов на изменения',
'Menu:Change:Shortcuts' => 'Ярлыки',
'Menu:Change:Shortcuts+' => 'Ярлыки',
'Menu:WaitingAcceptance' => 'Ожидающие принятия',
'Menu:WaitingAcceptance+' => 'Изменения, ожидающие принятия',
'Menu:WaitingApproval' => 'Ожидающие утверждения',
'Menu:WaitingApproval+' => 'Изменения, ожидающие утверждения',
'Menu:Changes' => 'Открытые',
'Menu:Changes+' => 'Открытые изменения',
'Menu:MyChanges' => 'Назначенные мне',
'Menu:MyChanges+' => 'Изменения, назначенные мне',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Изменения по категориям за 7 дней',
'UI-ChangeManagementOverview-Last-7-days' => 'Количество изменений за 7 дней',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Изменения по домену за 7 дней',
'UI-ChangeManagementOverview-ChangeByStatus-last-7-days' => 'Изменения по статусу за 7 дней',
));
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: Change
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Change' => 'Изменение',
'Class:Change+' => '',
'Class:Change/Attribute:status' => 'Статус',
'Class:Change/Attribute:status+' => '',
'Class:Change/Attribute:status/Value:new' => 'Новый',
'Class:Change/Attribute:status/Value:new+' => '',
'Class:Change/Attribute:status/Value:assigned' => 'Назначен',
'Class:Change/Attribute:status/Value:assigned+' => '',
'Class:Change/Attribute:status/Value:planned' => 'Запланировано',
'Class:Change/Attribute:status/Value:planned+' => '',
'Class:Change/Attribute:status/Value:rejected' => 'Отклонён',
'Class:Change/Attribute:status/Value:rejected+' => '',
'Class:Change/Attribute:status/Value:approved' => 'Утверждён',
'Class:Change/Attribute:status/Value:approved+' => '',
'Class:Change/Attribute:status/Value:closed' => 'Закрыт',
'Class:Change/Attribute:status/Value:closed+' => '',
'Class:Change/Attribute:category' => 'Категория',
'Class:Change/Attribute:category+' => '',
'Class:Change/Attribute:category/Value:application' => 'Приложение',
'Class:Change/Attribute:category/Value:application+' => 'Приложение',
'Class:Change/Attribute:category/Value:hardware' => 'Оборудование',
'Class:Change/Attribute:category/Value:hardware+' => 'Оборудование',
'Class:Change/Attribute:category/Value:network' => 'Сеть',
'Class:Change/Attribute:category/Value:network+' => 'Сеть',
'Class:Change/Attribute:category/Value:other' => 'Другое',
'Class:Change/Attribute:category/Value:other+' => 'Другое',
'Class:Change/Attribute:category/Value:software' => 'Программное обеспечение',
'Class:Change/Attribute:category/Value:software+' => 'Программное обеспечение',
'Class:Change/Attribute:category/Value:system' => 'Система',
'Class:Change/Attribute:category/Value:system+' => 'Система',
'Class:Change/Attribute:reject_reason' => 'Причина отклонения',
'Class:Change/Attribute:reject_reason+' => '',
'Class:Change/Attribute:changemanager_id' => 'Менеджер изменения',
'Class:Change/Attribute:changemanager_id+' => '',
'Class:Change/Attribute:changemanager_email' => 'Email менеджера',
'Class:Change/Attribute:changemanager_email+' => '',
'Class:Change/Attribute:parent_id' => 'Родительское изменение',
'Class:Change/Attribute:parent_id+' => '',
'Class:Change/Attribute:parent_name' => 'Родительское изменение',
'Class:Change/Attribute:parent_name+' => '',
'Class:Change/Attribute:creation_date' => 'Дата создания',
'Class:Change/Attribute:creation_date+' => '',
'Class:Change/Attribute:approval_date' => 'Дата утверждения',
'Class:Change/Attribute:approval_date+' => '',
'Class:Change/Attribute:fallback_plan' => 'План отката',
'Class:Change/Attribute:fallback_plan+' => '',
'Class:Change/Attribute:related_request_list' => 'Связанные запросы',
'Class:Change/Attribute:related_request_list+' => 'Связанные запросы',
'Class:Change/Attribute:related_incident_list' => 'Связанные инциденты',
'Class:Change/Attribute:related_incident_list+' => 'Связанные инциденты',
'Class:Change/Attribute:related_problems_list' => 'Связанные проблемы',
'Class:Change/Attribute:related_problems_list+' => 'Связанные проблемы',
'Class:Change/Attribute:child_changes_list' => 'Дочерние изменения',
'Class:Change/Attribute:child_changes_list+' => 'Дочерние изменения',
'Class:Change/Attribute:parent_id_friendlyname' => 'Родительское изменение',
'Class:Change/Attribute:parent_id_friendlyname+' => '',
'Class:Change/Stimulus:ev_assign' => 'Назначить',
'Class:Change/Stimulus:ev_assign+' => '',
'Class:Change/Stimulus:ev_plan' => 'Планировать',
'Class:Change/Stimulus:ev_plan+' => '',
'Class:Change/Stimulus:ev_reject' => 'Отклонить',
'Class:Change/Stimulus:ev_reject+' => '',
'Class:Change/Stimulus:ev_reopen' => 'Вновь открыть',
'Class:Change/Stimulus:ev_reopen+' => '',
'Class:Change/Stimulus:ev_approve' => 'Утвердить',
'Class:Change/Stimulus:ev_approve+' => '',
'Class:Change/Stimulus:ev_finish' => 'Закрыть',
'Class:Change/Stimulus:ev_finish+' => '',
'Class:Change/Attribute:outage' => 'Простой услуги',
'Class:Change/Attribute:outage+' => '',
'Class:Change/Attribute:outage/Value:no' => 'Нет',
'Class:Change/Attribute:outage/Value:no+' => '',
'Class:Change/Attribute:outage/Value:yes' => 'Да',
'Class:Change/Attribute:outage/Value:yes+' => '',
));

View File

@@ -552,7 +552,7 @@
<static>false</static>
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[ public function DBDeleteSingleObject()
<code><![CDATA[ public function DBDeleteSingleObject(&$oDeletionPlan)
{
if (MetaModel::GetConfig()->Get('demo_mode'))
{
@@ -1582,8 +1582,7 @@
$sStateAttCode = MetaModel::GetStateAttributeCode($sSubClass);
if ($sStateAttCode != '')
{
// Todo: base the search condition on operational_status = 'ongoing' for a more flexible behavior
$oSearch = DBSearch::FromOQL("SELECT $sSubClass AS t JOIN $sLnkClass AS lnk ON lnk.$sExtKeyToRemote = t.id WHERE lnk.$sExtKeyToMe = :myself AND t.$sStateAttCode NOT IN ('rejected', 'resolved', 'closed')", array('myself' => $this->GetKey()));
$oSearch = DBSearch::FromOQL("SELECT $sSubClass AS t JOIN $sLnkClass AS lnk ON lnk.$sExtKeyToRemote = t.id WHERE $sExtKeyToMe = :myself AND $sStateAttCode NOT IN ('rejected', 'resolved', 'closed')", array('myself' => $this->GetKey()));
$aSearches[$sSubClass] = $oSearch;
$oSet = new DBObjectSet($oSearch);

File diff suppressed because it is too large Load Diff

View File

@@ -105,7 +105,7 @@ try
{
$oP->add("<div class=\"header_message message_info\">Sorry, iTop is in <b>demonstration mode</b>: the configuration file cannot be edited.</div>");
}
else if (MetaModel::GetModuleSetting('itop-config', 'config_editor', '') == 'disabled')
if (MetaModel::GetModuleSetting('itop-config', 'config_editor', '') == 'disabled')
{
$oP->add("<div class=\"header_message message_info\">iTop interactive edition of the configuration as been disabled. See <tt>'config_editor' => 'disabled'</tt> in the configuration file.</div>");
}

View File

@@ -11,7 +11,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
'Menu:ConfigEditor' => 'Konfiguration',
'config-edit-title' => 'Konfigurations-Editor',
'config-edit-intro' => 'Seien sie bei der Bearbeitung der Konfigurationsdatei sehr vorsichtig.',
'config-edit-intro' => 'Seien sie bei der Bearbeitung der Konfigurationsdatei sehr vorsichtig. Normalerweise sollten es ausreichen die Einträge im oberen Teil der Konfiguration zu bearbeiten (Bsp.: die globalen Konfigurations- und Moduleinstellungen).',
'config-apply' => 'Anwenden',
'config-cancel' => 'Zurücksetzen',
'config-confirm-cancel' => 'Ihre Änderungen werden nicht gespeichert.',

View File

@@ -10,7 +10,7 @@ Dict::Add('EN US', 'English', 'English', array(
'Menu:ConfigEditor' => 'Configuration',
'config-edit-title' => 'Configuration File Editor',
'config-edit-intro' => 'Be very cautious when editing the configuration file.',
'config-edit-intro' => 'Be very cautious when editing the configuration file. In particular, only the upper items (i.e. the global configuration and modules settings) should be edited.',
'config-apply' => 'Apply',
'config-cancel' => 'Reset',
'config-confirm-cancel' => 'Your changes will be lost.',

View File

@@ -10,7 +10,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Menu:ConfigEditor' => 'Configuration',
'config-edit-title' => 'Editeur du Fichier de Configuration',
'config-edit-intro' => 'Attention: une configuration incorrecte peut rendre iTop inopérant pour tous les utilisateurs!',
'config-edit-intro' => 'Attention: une configuration incorrecte peut rendre iTop indisponible. En particulier, vous ne devriez éditer QUE les deux premiers éléments, à savoir la configuration globale et la configuration des modules.',
'config-save' => 'Appliquer',
'config-restore' => 'Réinitialiser',
'config-confirm-cancel' => 'Vos modifications seront perdues.',

View File

@@ -1,25 +0,0 @@
<?php
/**
* Локализация интерфейса Combodo iTop подготовлена сообществом iTop по-русски http://community.itop-itsm.ru.
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @link http://community.itop-itsm.ru iTop Russian Community
* @link https://github.com/itop-itsm-ru/itop-rus
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*
*/
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Menu:ConfigEditor' => 'Конфигурация',
'config-edit-title' => 'Редактор файла конфигурации',
'config-edit-intro' => 'Будьте очень осторожны при редактировании файла конфигурации. В частности, могут быть отредактированы только верхние элементы (т.е. глобальная конфигурация и настройки модулей).',
'config-apply' => 'Применить',
'config-cancel' => 'Сбросить',
'config-confirm-cancel' => 'Ваши изменения будут утеряны.',
'config-no-change' => 'Изменений нет: файл не был изменён.',
'config-parse-error' => 'Строка %2$d: %1$s.<br/>Файл не был обновлен.',
'config-current-line' => 'Редактируемая строка: %1$s',
));
?>

View File

@@ -1229,7 +1229,7 @@
if (!MetaModel::IsValidClass('UserRequest')) return true; // Do nothing
$oLog = $this->Get('public_log');
$sLogPublic = $oLog->GetModifiedEntry('html');
$sLogPublic = $oLog->GetModifiedEntry();
if ($sLogPublic != '')
{
$sOQL = "SELECT UserRequest WHERE parent_incident_id=:ticket";
@@ -1247,7 +1247,7 @@
}
$oLog = $this->Get('private_log');
$sLogPrivate = $oLog->GetModifiedEntry('html');
$sLogPrivate = $oLog->GetModifiedEntry();
if ($sLogPrivate != '')
{
$sOQL = "SELECT UserRequest WHERE parent_incident_id=:ticket";
@@ -1274,7 +1274,7 @@
<code><![CDATA[ public function UpdateChildIncidentLog()
{
$oLog = $this->Get('public_log');
$sLogPublic = $oLog->GetModifiedEntry('html');
$sLogPublic = $oLog->GetModifiedEntry();
if ($sLogPublic != '')
{
$sOQL = "SELECT Incident WHERE parent_incident_id=:ticket";
@@ -1292,7 +1292,7 @@
}
$oLog = $this->Get('private_log');
$sLogPrivate = $oLog->GetModifiedEntry('html');
$sLogPrivate = $oLog->GetModifiedEntry();
if ($sLogPrivate != '')
{
$sOQL = "SELECT Incident WHERE parent_incident_id=:ticket";

View File

@@ -1,217 +0,0 @@
<?php
/**
* Локализация интерфейса Combodo iTop подготовлена сообществом iTop по-русски http://community.itop-itsm.ru.
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @link http://community.itop-itsm.ru iTop Russian Community
* @link https://github.com/itop-itsm-ru/itop-rus
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*
*/
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Menu:IncidentManagement' => 'Управление инцидентами',
'Menu:IncidentManagement+' => 'Управление инцидентами',
'Menu:Incident:Overview' => 'Обзор',
'Menu:Incident:Overview+' => 'Обзор',
'Menu:NewIncident' => 'Новый инцидент',
'Menu:NewIncident+' => 'Создать новый инцидент',
'Menu:SearchIncidents' => 'Поиск инцидентов',
'Menu:SearchIncidents+' => 'Поиск инцидентов',
'Menu:Incident:Shortcuts' => 'Ярлыки',
'Menu:Incident:Shortcuts+' => 'Ярлыки',
'Menu:Incident:MyIncidents' => 'Назначенные мне',
'Menu:Incident:MyIncidents+' => 'Инциденты, назначенные мне (в качестве агента)',
'Menu:Incident:EscalatedIncidents' => 'Эскалированные',
'Menu:Incident:EscalatedIncidents+' => 'Эскалированные инциденты',
'Menu:Incident:OpenIncidents' => 'Открытые',
'Menu:Incident:OpenIncidents+' => 'Открытые инциденты',
'UI-IncidentManagementOverview-IncidentByPriority-last-14-days' => 'Инциденты по приоритету за 14 дней',
'UI-IncidentManagementOverview-Last-14-days' => 'Количество инцидентов за 14 дней',
'UI-IncidentManagementOverview-OpenIncidentByStatus' => 'Открытые инциденты по статусу',
'UI-IncidentManagementOverview-OpenIncidentByAgent' => 'Открытые инциденты по агенту',
'UI-IncidentManagementOverview-OpenIncidentByCustomer' => 'Открытые инциденты по заказчику',
));
//
// Class: Incident
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Incident' => 'Инцидент',
'Class:Incident+' => '',
'Class:Incident/Attribute:status' => 'Статус',
'Class:Incident/Attribute:status+' => '',
'Class:Incident/Attribute:status/Value:new' => 'Новый',
'Class:Incident/Attribute:status/Value:new+' => '',
'Class:Incident/Attribute:status/Value:escalated_tto' => 'Эскалация TTO',
'Class:Incident/Attribute:status/Value:escalated_tto+' => '',
'Class:Incident/Attribute:status/Value:assigned' => 'Назначен',
'Class:Incident/Attribute:status/Value:assigned+' => '',
'Class:Incident/Attribute:status/Value:escalated_ttr' => 'Эскалация TTR',
'Class:Incident/Attribute:status/Value:escalated_ttr+' => '',
'Class:Incident/Attribute:status/Value:waiting_for_approval' => 'Ожидание утверждения',
'Class:Incident/Attribute:status/Value:waiting_for_approval+' => '',
'Class:Incident/Attribute:status/Value:pending' => 'В ожидании',
'Class:Incident/Attribute:status/Value:pending+' => '',
'Class:Incident/Attribute:status/Value:resolved' => 'Решенный',
'Class:Incident/Attribute:status/Value:resolved+' => '',
'Class:Incident/Attribute:status/Value:closed' => 'Закрыт',
'Class:Incident/Attribute:status/Value:closed+' => '',
'Class:Incident/Attribute:impact' => 'Влияние',
'Class:Incident/Attribute:impact+' => '',
'Class:Incident/Attribute:impact/Value:1' => 'Департамент',
'Class:Incident/Attribute:impact/Value:1+' => '',
'Class:Incident/Attribute:impact/Value:2' => 'Служба',
'Class:Incident/Attribute:impact/Value:2+' => '',
'Class:Incident/Attribute:impact/Value:3' => 'Персона',
'Class:Incident/Attribute:impact/Value:3+' => '',
'Class:Incident/Attribute:priority' => 'Приоритет',
'Class:Incident/Attribute:priority+' => '',
'Class:Incident/Attribute:priority/Value:1' => 'Критический',
'Class:Incident/Attribute:priority/Value:1+' => 'Критический',
'Class:Incident/Attribute:priority/Value:2' => 'Высокий',
'Class:Incident/Attribute:priority/Value:2+' => 'Высокий',
'Class:Incident/Attribute:priority/Value:3' => 'Средний',
'Class:Incident/Attribute:priority/Value:3+' => 'Средний',
'Class:Incident/Attribute:priority/Value:4' => 'Низкий',
'Class:Incident/Attribute:priority/Value:4+' => 'Низкий',
'Class:Incident/Attribute:urgency' => 'Срочность',
'Class:Incident/Attribute:urgency+' => '',
'Class:Incident/Attribute:urgency/Value:1' => 'Критическая',
'Class:Incident/Attribute:urgency/Value:1+' => 'Критическая',
'Class:Incident/Attribute:urgency/Value:2' => 'Высокая',
'Class:Incident/Attribute:urgency/Value:2+' => 'Высокая',
'Class:Incident/Attribute:urgency/Value:3' => 'Средняя',
'Class:Incident/Attribute:urgency/Value:3+' => 'Средняя',
'Class:Incident/Attribute:urgency/Value:4' => 'Низкая',
'Class:Incident/Attribute:urgency/Value:4+' => 'Низкая',
'Class:Incident/Attribute:origin' => 'Источник',
'Class:Incident/Attribute:origin+' => '',
'Class:Incident/Attribute:origin/Value:mail' => 'Почта',
'Class:Incident/Attribute:origin/Value:mail+' => 'Почта',
'Class:Incident/Attribute:origin/Value:monitoring' => 'Мониторинг',
'Class:Incident/Attribute:origin/Value:monitoring+' => 'Мониторинг',
'Class:Incident/Attribute:origin/Value:phone' => 'Телефон',
'Class:Incident/Attribute:origin/Value:phone+' => 'Телефон',
'Class:Incident/Attribute:origin/Value:portal' => 'Портал',
'Class:Incident/Attribute:origin/Value:portal+' => 'Портал',
'Class:Incident/Attribute:service_id' => 'Услуга',
'Class:Incident/Attribute:service_id+' => '',
'Class:Incident/Attribute:service_name' => 'Услуга',
'Class:Incident/Attribute:service_name+' => '',
'Class:Incident/Attribute:servicesubcategory_id' => 'Подкатегория',
'Class:Incident/Attribute:servicesubcategory_id+' => 'Подкатегория услуги',
'Class:Incident/Attribute:servicesubcategory_name' => 'Подкатегория услуги',
'Class:Incident/Attribute:servicesubcategory_name+' => '',
'Class:Incident/Attribute:escalation_flag' => '«Флаг эскалации',
'Class:Incident/Attribute:escalation_flag+' => 'Флаг повышенного приоритета',
'Class:Incident/Attribute:escalation_flag/Value:no' => 'Нет',
'Class:Incident/Attribute:escalation_flag/Value:no+' => 'Нет',
'Class:Incident/Attribute:escalation_flag/Value:yes' => 'Да',
'Class:Incident/Attribute:escalation_flag/Value:yes+' => 'Да',
'Class:Incident/Attribute:escalation_reason' => 'Причина эскалации',
'Class:Incident/Attribute:escalation_reason+' => '',
'Class:Incident/Attribute:assignment_date' => 'Дата назначения',
'Class:Incident/Attribute:assignment_date+' => '',
'Class:Incident/Attribute:resolution_date' => 'Дата решения',
'Class:Incident/Attribute:resolution_date+' => '',
'Class:Incident/Attribute:last_pending_date' => 'Дата последнего ожидания',
'Class:Incident/Attribute:last_pending_date+' => '',
'Class:Incident/Attribute:cumulatedpending' => 'Накопленное ожидание',
'Class:Incident/Attribute:cumulatedpending+' => '',
'Class:Incident/Attribute:tto' => 'TTO',
'Class:Incident/Attribute:tto+' => '',
'Class:Incident/Attribute:ttr' => 'TTR',
'Class:Incident/Attribute:ttr+' => '',
'Class:Incident/Attribute:tto_escalation_deadline' => 'Срок TTO',
'Class:Incident/Attribute:tto_escalation_deadline+' => 'Крайний срок назаначения агента (принятия в работу) по текущему SLA',
'Class:Incident/Attribute:sla_tto_passed' => 'SLA TTO пропущено',
'Class:Incident/Attribute:sla_tto_passed+' => '',
'Class:Incident/Attribute:sla_tto_over' => 'SLA TTO превышено',
'Class:Incident/Attribute:sla_tto_over+' => '',
'Class:Incident/Attribute:ttr_escalation_deadline' => 'Срок TTR',
'Class:Incident/Attribute:ttr_escalation_deadline+' => 'Крайний срок решения по текущему SLA',
'Class:Incident/Attribute:sla_ttr_passed' => 'SLA TTR пропущено',
'Class:Incident/Attribute:sla_ttr_passed+' => '',
'Class:Incident/Attribute:sla_ttr_over' => 'SLA TTR превышено',
'Class:Incident/Attribute:sla_ttr_over+' => '',
'Class:Incident/Attribute:time_spent' => 'Время на решение',
'Class:Incident/Attribute:time_spent+' => '',
'Class:Incident/Attribute:resolution_code' => 'Код решения',
'Class:Incident/Attribute:resolution_code+' => '',
'Class:Incident/Attribute:resolution_code/Value:assistance' => 'Помощь',
'Class:Incident/Attribute:resolution_code/Value:assistance+' => 'Помощь',
'Class:Incident/Attribute:resolution_code/Value:bug fixed' => 'Исправление ошибки',
'Class:Incident/Attribute:resolution_code/Value:bug fixed+' => 'Исправление ошибки',
'Class:Incident/Attribute:resolution_code/Value:hardware repair' => 'Ремонт оборудования',
'Class:Incident/Attribute:resolution_code/Value:hardware repair+' => 'Ремонт оборудования',
'Class:Incident/Attribute:resolution_code/Value:other' => 'Другое',
'Class:Incident/Attribute:resolution_code/Value:other+' => 'Другое',
'Class:Incident/Attribute:resolution_code/Value:software patch' => 'Патч ПО',
'Class:Incident/Attribute:resolution_code/Value:software patch+' => 'Патч ПО',
'Class:Incident/Attribute:resolution_code/Value:system update' => 'Обновление системы',
'Class:Incident/Attribute:resolution_code/Value:system update+' => 'Обновление системы',
'Class:Incident/Attribute:resolution_code/Value:training' => 'Обучение',
'Class:Incident/Attribute:resolution_code/Value:training+' => 'Обучение',
'Class:Incident/Attribute:solution' => 'Описание решения',
'Class:Incident/Attribute:solution+' => '',
'Class:Incident/Attribute:pending_reason' => 'Причина ожидания',
'Class:Incident/Attribute:pending_reason+' => '',
'Class:Incident/Attribute:parent_incident_id' => 'Родительский инцидент',
'Class:Incident/Attribute:parent_incident_id+' => '',
'Class:Incident/Attribute:parent_problem_id' => 'Родительская проблема',
'Class:Incident/Attribute:parent_problem_id+' => '',
'Class:Incident/Attribute:parent_problem_ref' => 'Родительская проблема',
'Class:Incident/Attribute:parent_problem_ref+' => '',
'Class:Incident/Attribute:parent_incident_ref' => 'Родительский инцидент',
'Class:Incident/Attribute:parent_incident_ref+' => '',
'Class:Incident/Attribute:parent_change_id' => 'Родительское изменение',
'Class:Incident/Attribute:parent_change_id+' => '',
'Class:Incident/Attribute:parent_change_ref' => 'Родительское изменение',
'Class:Incident/Attribute:parent_change_ref+' => '',
'Class:Incident/Attribute:child_incidents_list' => 'Дочерние инциденты',
'Class:Incident/Attribute:child_incidents_list+' => 'Все инциденты, связанные с этим инцидентом',
'Class:Incident/Attribute:related_request_list' => 'Запросы',
'Class:Incident/Attribute:related_request_list+' => 'Все пользовательские запросы, связанные с этим инцидентом',
'Class:Incident/Attribute:public_log' => 'Общий журнал',
'Class:Incident/Attribute:public_log+' => 'Информация в общем журнале доступна для пользователей портала',
'Class:Incident/Attribute:user_satisfaction' => 'Удовлетворенность пользователя',
'Class:Incident/Attribute:user_satisfaction+' => '',
'Class:Incident/Attribute:user_satisfaction/Value:1' => 'Очень доволен',
'Class:Incident/Attribute:user_satisfaction/Value:1+' => 'Очень доволен',
'Class:Incident/Attribute:user_satisfaction/Value:2' => 'Вполне доволен',
'Class:Incident/Attribute:user_satisfaction/Value:2+' => 'Вполне доволен',
'Class:Incident/Attribute:user_satisfaction/Value:3' => 'Скорее недоволен',
'Class:Incident/Attribute:user_satisfaction/Value:3+' => 'Скорее недоволен',
'Class:Incident/Attribute:user_satisfaction/Value:4' => 'Очень недоволен',
'Class:Incident/Attribute:user_satisfaction/Value:4+' => 'Очень недоволен',
'Class:Incident/Attribute:user_comment' => 'Комментарий пользователя',
'Class:Incident/Attribute:user_comment+' => '',
'Class:Incident/Attribute:parent_incident_id_friendlyname' => 'Родительский инцидент',
'Class:Incident/Attribute:parent_incident_id_friendlyname+' => '',
'Class:Incident/Stimulus:ev_assign' => 'Назначить',
'Class:Incident/Stimulus:ev_assign+' => '',
'Class:Incident/Stimulus:ev_reassign' => 'Переназначить',
'Class:Incident/Stimulus:ev_reassign+' => '',
'Class:Incident/Stimulus:ev_pending' => 'В ожидание',
'Class:Incident/Stimulus:ev_pending+' => '',
'Class:Incident/Stimulus:ev_timeout' => 'Таймаут',
'Class:Incident/Stimulus:ev_timeout+' => '',
'Class:Incident/Stimulus:ev_autoresolve' => 'Автоматическое решение',
'Class:Incident/Stimulus:ev_autoresolve+' => '',
'Class:Incident/Stimulus:ev_autoclose' => 'Автоматическое закрытие',
'Class:Incident/Stimulus:ev_autoclose+' => '',
'Class:Incident/Stimulus:ev_resolve' => 'Отметить как решенный',
'Class:Incident/Stimulus:ev_resolve+' => '',
'Class:Incident/Stimulus:ev_close' => 'Закрыть',
'Class:Incident/Stimulus:ev_close+' => '',
'Class:Incident/Stimulus:ev_reopen' => 'Вновь открыть',
'Class:Incident/Stimulus:ev_reopen+' => '',
'Class:Incident/Error:CannotAssignParentIncidentIdToSelf' => 'Невозможно назначить этот же инцидент в качестве родительского',
'Class:Incident/Method:ResolveChildTickets' => 'ResolveChildTickets',
'Class:Incident/Method:ResolveChildTickets+' => 'Cascade the resolution to child ticket (ev_autoresolve), and align the following characteristics: service, team, agent, resolution info',
'Tickets:Related:OpenIncidents' => 'Открытые инциденты',
));

View File

@@ -622,7 +622,7 @@
<parent_att/>
<name_att/>
<tooltip_att/>
<title>Class:FAQCategory</title>
<title>Catégories</title>
<actions/>
<levels>
<level id="1">
@@ -630,7 +630,7 @@
<parent_att>category_id</parent_att>
<name_att>title</name_att>
<tooltip_att>summary</tooltip_att>
<title>Class:FAQ</title>
<title>FAQs</title>
<fields>
<field id="error_code"/>
<field id="key_words">

View File

@@ -125,8 +125,5 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:lnkDocumentToError/Attribute:error_name+' => '',
'Class:FAQ/Attribute:category_name' => 'Kategoriename',
'Class:FAQ/Attribute:category_name+' => '',
'Brick:Portal:FAQ:Menu' => 'FAQ',
'Brick:Portal:FAQ:Title' => 'Oft gestellte Fragen (FAQs)',
'Brick:Portal:FAQ:Title+' => '<p>In Eile?</p><p>Sehen Sie sich die meistgestellten Fragen an (FAQs) und finden Sie (eventuell) die Antwort direkt dort.</p>',
));
?>

View File

@@ -187,8 +187,5 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Menu:FAQ' => 'Preguntas y Respuestas Frecuentes',
'Menu:FAQ+' => 'Preguntas y Respuestas Frecuentes',
'Brick:Portal:FAQ:Menu' => 'FAQ',
'Brick:Portal:FAQ:Title' => 'Preguntas y Respuestas Frecuentes',
'Brick:Portal:FAQ:Title+' => '<p>¿En una prisa?</p><p>Vea la lista de las preguntas más comunes y encontrará (tal vez) la respuesta inmediata a sus necesidades.</p>',
));
?>

View File

@@ -2,14 +2,48 @@
/**
* Локализация интерфейса Combodo iTop подготовлена сообществом iTop по-русски http://community.itop-itsm.ru.
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @license http://opensource.org/licenses/AGPL-3.0
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @link http://community.itop-itsm.ru iTop Russian Community
* @link https://github.com/itop-itsm-ru/itop-rus
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*
* Инструкция по установке
*
* Процесс установки заключается в замене имеющихся локализационных файлов полученными и последующем запуске процедуры обновления iTop для перекомпиляции кода.
* 1. Скопируйте с заменой два полученных файла из "itop-rus/dictionaries" в "путь/до/вашего/itop/dictionaries".
* 2. Скопируйте с заменой полученные файлы "itop-rus/datamodels/2.x/название-модуля/ru.dict.название-модуля.php" в "путь/до/вашего/itop/datamodels/2.x/название-модуля".
* 3. Перейдите по адресу "http://адрес/вашего/itop/setup", при этом файл "путь/до/вашего/itop/conf/production/config-itop.php" должен быть доступен для записи.
* 4. На второй странице установщика выберите "Upgrade an existing iTop instance" и следуйте дальнейшим инструкциям установщика.
*
* Ответы на вопросы по установке и использованию переводов, а также на любые другие вопросы по iTop всегда можно получить на сайте сообщества iTop по-русски http://community.itop-itsm.ru.
*
*/
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//////////////////////////////////////////////////////////////////////
// Classes in 'bizmodel'
//////////////////////////////////////////////////////////////////////
//
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: KnownError
//
@@ -21,11 +55,11 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:KnownError/Attribute:name+' => '',
'Class:KnownError/Attribute:org_id' => 'Организация',
'Class:KnownError/Attribute:org_id+' => '',
'Class:KnownError/Attribute:cust_name' => 'Организация',
'Class:KnownError/Attribute:cust_name' => 'Имя клиента',
'Class:KnownError/Attribute:cust_name+' => '',
'Class:KnownError/Attribute:problem_id' => 'Проблема',
'Class:KnownError/Attribute:problem_id+' => '',
'Class:KnownError/Attribute:problem_ref' => 'Проблема',
'Class:KnownError/Attribute:problem_ref' => 'Ссылка на проблему',
'Class:KnownError/Attribute:problem_ref+' => '',
'Class:KnownError/Attribute:symptom' => 'Проявление',
'Class:KnownError/Attribute:symptom+' => '',
@@ -68,11 +102,11 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkErrorToFunctionalCI+' => 'Infra related to a known error',
'Class:lnkErrorToFunctionalCI/Attribute:functionalci_id' => 'КЕ',
'Class:lnkErrorToFunctionalCI/Attribute:functionalci_id+' => '',
'Class:lnkErrorToFunctionalCI/Attribute:functionalci_name' => 'КЕ',
'Class:lnkErrorToFunctionalCI/Attribute:functionalci_name' => 'Имя КЕ',
'Class:lnkErrorToFunctionalCI/Attribute:functionalci_name+' => '',
'Class:lnkErrorToFunctionalCI/Attribute:error_id' => 'Известная ошибка',
'Class:lnkErrorToFunctionalCI/Attribute:error_id+' => '',
'Class:lnkErrorToFunctionalCI/Attribute:error_name' => 'Известная ошибка',
'Class:lnkErrorToFunctionalCI/Attribute:error_name' => мя известной ошибки',
'Class:lnkErrorToFunctionalCI/Attribute:error_name+' => '',
'Class:lnkErrorToFunctionalCI/Attribute:reason' => 'Причина',
'Class:lnkErrorToFunctionalCI/Attribute:reason+' => '',
@@ -87,11 +121,11 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkDocumentToError+' => 'A link between a document and a known error',
'Class:lnkDocumentToError/Attribute:document_id' => 'Документ',
'Class:lnkDocumentToError/Attribute:document_id+' => '',
'Class:lnkDocumentToError/Attribute:document_name' => 'Документ',
'Class:lnkDocumentToError/Attribute:document_name' => 'Имя документа',
'Class:lnkDocumentToError/Attribute:document_name+' => '',
'Class:lnkDocumentToError/Attribute:error_id' => 'Известная ошибка',
'Class:lnkDocumentToError/Attribute:error_id+' => '',
'Class:lnkDocumentToError/Attribute:error_name' => 'Известная ошибка',
'Class:lnkDocumentToError/Attribute:error_name' => 'Часто задаваемые вопросы',
'Class:lnkDocumentToError/Attribute:error_name+' => '',
'Class:lnkDocumentToError/Attribute:link_type' => 'Тип связи',
'Class:lnkDocumentToError/Attribute:link_type+' => '',
@@ -112,7 +146,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:FAQ/Attribute:description+' => '',
'Class:FAQ/Attribute:category_id' => 'Категория',
'Class:FAQ/Attribute:category_id+' => '',
'Class:FAQ/Attribute:category_name' => 'Категория',
'Class:FAQ/Attribute:category_name' => 'Имя категории',
'Class:FAQ/Attribute:category_name+' => '',
'Class:FAQ/Attribute:error_code' => 'Код ошибки',
'Class:FAQ/Attribute:error_code+' => '',
@@ -125,31 +159,27 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:FAQCategory' => 'Категории FAQ',
'Class:FAQCategory+' => 'Категории FAQ',
'Class:FAQCategory/Attribute:name' => 'Название',
'Class:FAQCategory' => 'Категории ЧаВо',
'Class:FAQCategory+' => 'Category for FAQ',
'Class:FAQCategory/Attribute:name' => 'Имя',
'Class:FAQCategory/Attribute:name+' => '',
'Class:FAQCategory/Attribute:faq_list' => 'FAQ',
'Class:FAQCategory/Attribute:faq_list+' => 'Связанные FAQ',
'Class:FAQCategory/Attribute:faq_list' => 'ЧаВо',
'Class:FAQCategory/Attribute:faq_list+' => 'All the frequently asked questions related to this category',
));
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Menu:ProblemManagement' => 'Управление проблемами',
'Menu:ProblemManagement+' => 'Управление проблемами',
'Menu:Problem:Shortcuts' => 'Ярлыки',
'Menu:NewError' => 'Новая известная ошибка',
'Menu:NewError+' => 'Создать новую известную ошибку',
'Menu:SearchError' => 'Поиск известных ошибок',
'Menu:SearchError+' => 'Поиск известных ошибок',
'Menu:Problem:KnownErrors' => 'Известные ошибки',
'Menu:Problem:KnownErrors+' => 'База известных ошибок',
'Menu:ProblemManagement' => 'Problem Management',
'Menu:ProblemManagement+' => 'Problem Management',
'Menu:Problem:Shortcuts' => 'Shortcuts',
'Menu:NewError' => 'Создать известную ошибку',
'Menu:NewError+' => 'Creation of a new known error',
'Menu:SearchError' => 'Найти известную ошибку',
'Menu:SearchError+' => 'Search for known errors',
'Menu:Problem:KnownErrors' => 'Известные ошибки',
'Menu:Problem:KnownErrors+' => 'База известных ошибок',
'Menu:FAQCategory' => 'Категории FAQ',
'Menu:FAQCategory+' => 'Категории FAQ',
'Menu:FAQ' => 'FAQ',
'Menu:FAQ+' => 'Часто задаваемые вопросы',
'Brick:Portal:FAQ:Menu' => 'FAQ',
'Brick:Portal:FAQ:Title' => 'Часто задаваемые вопросы',
'Brick:Portal:FAQ:Title+' => '<p>Торопитесь?</p><p>Проверьте список часто задаваемых вопросов, возможно, ответ уже есть.</p>',
));
));
?>

View File

@@ -40,15 +40,13 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', array(
'Portal:Button:Add' => 'Přidat',
'Portal:Button:Remove' => 'Odebrat',
'Portal:Button:Delete' => 'Smazat',
'Portal:EnvironmentBanner:Title' => 'You are currently in <strong>%1$s</strong> mode~~',
'Portal:EnvironmentBanner:GoToProduction' => 'Go back to PRODUCTION mode~~',
'Error:HTTP:404' => 'Stránka nenalezena',
'Error:HTTP:404' => 'Stránka nenalezena',
'Error:HTTP:500' => 'Jejda! Nastal problém',
'Error:HTTP:GetHelp' => 'Kontaktujte prosím administrátora, pokud problém přetrvá.',
'Error:XHR:Fail' => 'Data se nepodařilo načíst, kontaktujte prosím administrátora.',
'Portal:Datatables:Language:Processing' => 'Počkejte prosím',
'Portal:Datatables:Language:Search' => 'Filtr :',
'Portal:Datatables:Language:LengthMenu' => 'Zobrazit _MENU_ položek na stránku',
'Portal:Datatables:Language:Search' => 'filtr :',
'Portal:Datatables:Language:LengthMenu' => 'Zobrazit _MENU_ položek na stránku',
'Portal:Datatables:Language:ZeroRecords' => 'Žádný výsledek',
'Portal:Datatables:Language:Info' => 'Stránka _PAGE_ z _PAGES_',
'Portal:Datatables:Language:InfoEmpty' => 'Žádná informace',
@@ -63,9 +61,6 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', array(
'Portal:Datatables:Language:Sort:Descending' => 'řadit sestupně',
'Portal:Autocomplete:NoResult' => 'Žádná data',
'Portal:Attachments:DropZone:Message' => 'Přesuňte soubory myší pro vložení',
'Portal:File:None' => 'No file',
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Open</a> / <a href="%4$s" class="file_download_link">Download</a>',
));
// UserProfile brick

View File

@@ -1,117 +0,0 @@
<?php
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @copyright Copyright (C) 2016 ITOMIG GmbH
* @license http://opensource.org/licenses/AGPL-3.0
*/
// Portal
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Page:DefaultTitle' => 'iTop - Benutzer Portal',
'Page:PleaseWait' => 'Bitte warten...',
'Page:Home' => 'Start',
'Page:GoPortalHome' => 'Startseite',
'Page:GoPreviousPage' => 'vorherige Seite',
'Portal:Button:Submit' => 'Abschicken',
'Portal:Button:Cancel' => 'Zurück',
'Portal:Button:Close' => 'Schließen',
'Portal:Button:Add' => 'Hinzu',
'Portal:Button:Remove' => 'Wegnehmen',
'Portal:Button:Delete' => 'Löschen',
'Portal:EnvironmentBanner:Title' => 'Sie sind im Moment im <strong>%1$s</strong> Modus',
'Portal:EnvironmentBanner:GoToProduction' => 'Zurück zum PRODUCTION Modus',
'Error:HTTP:404' => 'Seite nicht gefunden.',
'Error:HTTP:500' => 'Oops! Es ist ein Fehler aufgetreten.',
'Error:HTTP:GetHelp' => 'Bitte kontaktieren Sie Ihren iTop administrator falls das Problem öfter auftaucht.',
'Error:XHR:Fail' => 'Konnte Daten nicht laden, bitte kontaktieren Sie Ihren iTop administrator',
'Portal:Datatables:Language:Processing' => 'Bitte warten...',
'Portal:Datatables:Language:Search' => 'Filter :',
'Portal:Datatables:Language:LengthMenu' => 'Anzahl _MENU_ Einträge pro Seite',
'Portal:Datatables:Language:ZeroRecords' => 'Keine Resultate',
'Portal:Datatables:Language:Info' => 'Seite _PAGE_ von _PAGES_',
'Portal:Datatables:Language:InfoEmpty' => 'Keine Information',
'Portal:Datatables:Language:InfoFiltered' => 'gefiltert aus _MAX_ Resultaten',
'Portal:Datatables:Language:EmptyTable' => 'Keine Daten in dieser Tabelle verfügbar',
'Portal:Datatables:Language:DisplayLength:All' => 'Alle',
'Portal:Datatables:Language:Paginate:First' => '1.Seite',
'Portal:Datatables:Language:Paginate:Previous' => 'vorherige',
'Portal:Datatables:Language:Paginate:Next' => 'Nächste',
'Portal:Datatables:Language:Paginate:Last' => 'Letzte',
'Portal:Datatables:Language:Sort:Ascending' => 'wähle aufsteigende Sortierung',
'Portal:Datatables:Language:Sort:Descending' => 'wähle abfallende Sortierung',
'Portal:Autocomplete:NoResult' => 'keine Daten',
'Portal:Attachments:DropZone:Message' => 'Legen Sie hier Ihre Files ab, um sie als Anhang dem Ticket hinzuzufügen',
'Portal:File:None' => 'Kein File vorhanden',
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Öffnen</a> / <a href="%4$s" class="file_download_link">Download</a>',
));
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Brick:Portal:UserProfile:Name' => 'Benutzer Profil',
'Brick:Portal:UserProfile:Navigation:Dropdown:MyProfil' => 'Mein Profil',
'Brick:Portal:UserProfile:Navigation:Dropdown:Logout' => 'Abmelden',
'Brick:Portal:UserProfile:Password:Title' => 'Passwort',
'Brick:Portal:UserProfile:Password:ChoosePassword' => 'Passwort wählen',
'Brick:Portal:UserProfile:Password:ConfirmPassword' => 'Passwort bestätigen',
'Brick:Portal:UserProfile:Password:CantChangeContactAdministrator' => 'Um das Password zu ändern, kontaktieren Sie bitte Ihren iTop Administrator',
'Brick:Portal:UserProfile:Password:CantChangeForUnknownReason' => 'Kann das Passwort nicht ändern - bitte kontaktieren Sie Ihren iTop Administrator',
'Brick:Portal:UserProfile:PersonalInformations:Title' => 'Persönliche Informationen',
'Brick:Portal:UserProfile:Photo:Title' => 'Foto',
));
// BrowseBrick brick
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Brick:Portal:Browse:Name' => 'List durchgehen',
'Brick:Portal:Browse:Mode:List' => 'Liste',
'Brick:Portal:Browse:Mode:Tree' => 'Baum',
'Brick:Portal:Browse:Action:Drilldown' => 'Drilldown',
'Brick:Portal:Browse:Action:View' => 'Details',
'Brick:Portal:Browse:Action:Edit' => 'Editieren',
'Brick:Portal:Browse:Action:Create' => 'Erstellen',
'Brick:Portal:Browse:Action:CreateObjectFromThis' => 'Neue %1$s',
'Brick:Portal:Browse:Tree:ExpandAll' => 'Alle expandieren',
'Brick:Portal:Browse:Tree:CollapseAll' => 'Alle kollabieren',
'Brick:Portal:Browse:Filter:NoData' => 'Kein Eintrag',
));
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Brick:Portal:Manage:Name' => 'Einträge managen',
'Brick:Portal:Manage:Table:NoData' => 'Kein Eintrag.',
));
// ObjectBrick brick
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Brick:Portal:Object:Name' => 'Object',
'Brick:Portal:Object:Form:Create:Title' => 'Neue %1$s',
'Brick:Portal:Object:Form:Edit:Title' => 'Wird aktualisiert %2$s (%1$s)',
'Brick:Portal:Object:Form:View:Title' => '%1$s : %2$s',
'Brick:Portal:Object:Form:Stimulus:Title' => 'Bitte die folgendenen Informationen ausfüllen:',
'Brick:Portal:Object:Form:Message:Saved' => 'Saved',
'Brick:Portal:Object:Search:Regular:Title' => 'Select %1$s (%2$s)',
'Brick:Portal:Object:Search:Hierarchy:Title' => 'Select %1$s (%2$s)',
));
// CreateBrick brick
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Brick:Portal:Create:Name' => 'Schnelles Erstellen',
));
?>

View File

@@ -36,14 +36,12 @@ Dict::Add('EN US', 'English', 'English', array(
'Portal:Button:Add' => 'Add',
'Portal:Button:Remove' => 'Remove',
'Portal:Button:Delete' => 'Delete',
'Portal:EnvironmentBanner:Title' => 'You are currently in <strong>%1$s</strong> mode',
'Portal:EnvironmentBanner:GoToProduction' => 'Go back to PRODUCTION mode',
'Error:HTTP:404' => 'Page not found',
'Error:HTTP:500' => 'Oops! An error has occured.',
'Error:HTTP:GetHelp' => 'Please contact your iTop administrator if the problem keeps happening.',
'Error:XHR:Fail' => 'Could not load data, please contact your iTop administrator',
'Portal:Datatables:Language:Processing' => 'Please wait...',
'Portal:Datatables:Language:Search' => 'Filter:',
'Portal:Datatables:Language:Search' => 'filter :',
'Portal:Datatables:Language:LengthMenu' => 'Display _MENU_ items per page',
'Portal:Datatables:Language:ZeroRecords' => 'No result',
'Portal:Datatables:Language:Info' => 'Page _PAGE_ of _PAGES_',
@@ -59,9 +57,6 @@ Dict::Add('EN US', 'English', 'English', array(
'Portal:Datatables:Language:Sort:Descending' => 'enable for a descending sort',
'Portal:Autocomplete:NoResult' => 'No data',
'Portal:Attachments:DropZone:Message' => 'Drop your files to add them as attachments',
'Portal:File:None' => 'No file',
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Open</a> / <a href="%4$s" class="file_download_link">Download</a>',
));
// UserProfile brick

View File

@@ -1,118 +0,0 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
// Portal
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Page:DefaultTitle' => 'iTop User portal',
'Page:PleaseWait' => 'Please wait...',
'Page:Home' => 'Bienvenido',
'Page:GoPortalHome' => 'Regresar a bienvenida',
'Page:GoPreviousPage' => 'página anterior',
'Portal:Button:Submit' => 'Enviar',
'Portal:Button:Cancel' => 'Cancelar',
'Portal:Button:Close' => 'Cerrar',
'Portal:Button:Add' => 'Añadir',
'Portal:Button:Remove' => 'Eliminar',
'Portal:Button:Delete' => 'Borrar',
'Portal:EnvironmentBanner:Title' => 'You are currently in <strong>%1$s</strong> mode~~',
'Portal:EnvironmentBanner:GoToProduction' => 'Go back to PRODUCTION mode~~',
'Error:HTTP:404' => 'Página no encontrada',
'Error:HTTP:500' => '¡Vaya! Ha ocurrido un error.',
'Error:HTTP:GetHelp' => 'Póngase en contacto con el administrador de iTop si el problema persiste.',
'Error:XHR:Fail' => 'No se pudieron cargar datos, póngase en contacto con su administrador de iTop',
'Portal:Datatables:Language:Processing' => 'Por favor esperar...',
'Portal:Datatables:Language:Search' => 'Filtrar:',
'Portal:Datatables:Language:LengthMenu' => 'Mostrar _MENU_ elementos por página',
'Portal:Datatables:Language:ZeroRecords' => 'Sin resultados',
'Portal:Datatables:Language:Info' => 'Página _PAGE_ de _PAGES_',
'Portal:Datatables:Language:InfoEmpty' => 'Sin información',
'Portal:Datatables:Language:InfoFiltered' => 'Filtrada de _MAX_ elementos',
'Portal:Datatables:Language:EmptyTable' => 'No hay datos disponibles en esta tabla',
'Portal:Datatables:Language:DisplayLength:All' => 'Todas',
'Portal:Datatables:Language:Paginate:First' => 'primero',
'Portal:Datatables:Language:Paginate:Previous' => 'Anterior',
'Portal:Datatables:Language:Paginate:Next' => 'Siguiente',
'Portal:Datatables:Language:Paginate:Last' => 'Último',
'Portal:Datatables:Language:Sort:Ascending' => 'Habilitar para un orden ascendente',
'Portal:Datatables:Language:Sort:Descending' => 'Habilitar para un tipo descendente',
'Portal:Autocomplete:NoResult' => 'Sin datos',
'Portal:Attachments:DropZone:Message' => 'Agrega tus archivos para agregarlos como documentos adjuntos',
'Portal:File:None' => 'No file',
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Open</a> / <a href="%4$s" class="file_download_link">Download</a>',
));
// UserProfile brick
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Brick:Portal:UserProfile:Name' => 'Perfil del usuario',
'Brick:Portal:UserProfile:Navigation:Dropdown:MyProfil' => 'Mi perfil',
'Brick:Portal:UserProfile:Navigation:Dropdown:Logout' => 'Desconectarse',
'Brick:Portal:UserProfile:Password:Title' => 'Contraseña',
'Brick:Portal:UserProfile:Password:ChoosePassword' => 'Elegir una contraseña',
'Brick:Portal:UserProfile:Password:ConfirmPassword' => 'Confirmar contraseña',
'Brick:Portal:UserProfile:Password:CantChangeContactAdministrator' => 'Para cambiar su contraseña, póngase en contacto con su administrador de iTop',
'Brick:Portal:UserProfile:Password:CantChangeForUnknownReason' => 'No se puede cambiar la contraseña, póngase en contacto con el administrador de iTop',
'Brick:Portal:UserProfile:PersonalInformations:Title' => 'Informaciones personales',
'Brick:Portal:UserProfile:Photo:Title' => 'Foto',
));
// BrowseBrick brick
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Brick:Portal:Browse:Name' => 'Buscar en todos los elementos',
'Brick:Portal:Browse:Mode:List' => 'Lista',
'Brick:Portal:Browse:Mode:Tree' => 'Árbol',
'Brick:Portal:Browse:Action:Drilldown' => 'Desglose',
'Brick:Portal:Browse:Action:View' => 'Detalles',
'Brick:Portal:Browse:Action:Edit' => 'Editar',
'Brick:Portal:Browse:Action:Create' => 'Crear',
'Brick:Portal:Browse:Action:CreateObjectFromThis' => 'Nuevo %1$s',
'Brick:Portal:Browse:Tree:ExpandAll' => 'Expandir todo',
'Brick:Portal:Browse:Tree:CollapseAll' => 'Desplegar todo',
'Brick:Portal:Browse:Filter:NoData' => 'Sin objeto',
));
// ManageBrick brick
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Brick:Portal:Manage:Name' => 'Administrar elementos',
'Brick:Portal:Manage:Table:NoData' => 'Sin objeto.',
));
// ObjectBrick brick
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Brick:Portal:Object:Name' => 'Object',
'Brick:Portal:Object:Form:Create:Title' => 'New %1$s',
'Brick:Portal:Object:Form:Edit:Title' => 'Updating %2$s (%1$s)',
'Brick:Portal:Object:Form:View:Title' => '%1$s : %2$s',
'Brick:Portal:Object:Form:Stimulus:Title' => 'Please, fill the following informations:',
'Brick:Portal:Object:Form:Message:Saved' => 'Saved',
'Brick:Portal:Object:Search:Regular:Title' => 'Select %1$s (%2$s)',
'Brick:Portal:Object:Search:Hierarchy:Title' => 'Select %1$s (%2$s)',
));
// CreateBrick brick
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Brick:Portal:Create:Name' => 'Creación rápida',
));
?>

View File

@@ -36,8 +36,6 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Portal:Button:Add' => 'Ajouter',
'Portal:Button:Remove' => 'Enlever',
'Portal:Button:Delete' => 'Supprimer',
'Portal:EnvironmentBanner:Title' => 'Vous êtes dans le mode <strong>%1$s</strong>',
'Portal:EnvironmentBanner:GoToProduction' => 'Retourner au mode PRODUCTION',
'Error:HTTP:404' => 'Page non trouvée',
'Error:HTTP:500' => 'Oups ! Une erreur est survenue.',
'Error:HTTP:GetHelp' => 'Si le problème persiste, veuillez contacter votre administrateur iTop.',
@@ -59,9 +57,6 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Portal:Datatables:Language:Sort:Descending' => 'activer pour trier la colonne par ordre décroissant',
'Portal:Autocomplete:NoResult' => 'Aucun résultat',
'Portal:Attachments:DropZone:Message' => 'Déposez vos fichiers pour les ajouter en pièces jointes',
'Portal:File:None' => 'Aucun fichier',
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">Ouvrir</a> / <a href="%4$s" class="file_download_link">Télécharger</a>',
));
// UserProfile brick

View File

@@ -2,7 +2,7 @@
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-portal-base/1.0.1', array(
'itop-portal-base/1.0.0', array(
// Identification
'label' => 'Portal Development Library',
'category' => 'Portal',

View File

@@ -93,19 +93,11 @@ class BrowseBrickController extends BrickController
{
// Retrieving class alias for all depth
array_unshift($aLevelsClasses, $aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->GetClassAlias());
// Joining queries from bottom-up
if ($i < $iLoopMax)
{
$aRealiasingMap = array();
$aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search'] = $aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->Join($aLevelsProperties[$aLevelsPropertiesKeys[$i + 1]]['search'], DBSearch::JOIN_REFERENCED_BY, $aLevelsProperties[$aLevelsPropertiesKeys[$i + 1]]['parent_att'], TREE_OPERATOR_EQUALS, $aRealiasingMap);
foreach ($aLevelsPropertiesKeys as $sLevelAlias)
{
if (array_key_exists($sLevelAlias, $aRealiasingMap))
{
$aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->RenameAlias($aRealiasingMap[$sLevelAlias], $sLevelAlias);
}
}
$aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search'] = $aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->Join($aLevelsProperties[$aLevelsPropertiesKeys[$i + 1]]['search'], DBSearch::JOIN_REFERENCED_BY, $aLevelsProperties[$aLevelsPropertiesKeys[$i + 1]]['parent_att']);
}
// Adding search clause
@@ -176,7 +168,7 @@ class BrowseBrickController extends BrickController
}
}
$oQuery = $aLevelsProperties[$aLevelsPropertiesKeys[0]]['search'];
// Testing appropriate data loading mode if we are in auto
if ($sDataLoading === AbstractBrick::ENUM_DATA_LOADING_AUTO)
{
@@ -267,32 +259,7 @@ class BrowseBrickController extends BrickController
{
$oSet = new DBObjectSet($oQuery);
}
// Optimizing the ObjectSet to retrieve only necessary columns
$aColumnAttrs = array();
foreach ($oSet->GetFilter()->GetSelectedClasses() as $sTmpClassAlias => $sTmpClassName)
{
if (isset($aLevelsProperties[$sTmpClassAlias]))
{
$aTmpLevelProperties = $aLevelsProperties[$sTmpClassAlias];
// Mandatory main attribute
$aTmpColumnAttrs = array($aTmpLevelProperties['name_att']);
// Optionnal attributes, only if in list mode
if ($sBrowseMode === BrowseBrick::ENUM_BROWSE_MODE_LIST)
{
foreach ($aTmpLevelProperties['fields'] as $aTmpField)
{
$aTmpColumnAttrs[] = $aTmpField['code'];
}
}
$aColumnAttrs[$sTmpClassAlias] = $aTmpColumnAttrs;
}
}
$oSet->OptimizeColumnLoad($aColumnAttrs);
// Sorting objects through defined order (in DM)
$oSet->SetOrderByClasses();
// Retrieving results and organizing them for templating
$aItems = array();
while ($aCurrentRow = $oSet->FetchAssoc())
@@ -371,16 +338,10 @@ class BrowseBrickController extends BrickController
{
$sCurrentLevelAlias = $sLevelAliasPrefix . static::LEVEL_SEPARATOR . $aLevel['id'];
$oSearch = DBSearch::CloneWithAlias(DBSearch::FromOQL($aLevel['oql']), $sCurrentLevelAlias);
// Restricting to the allowed scope
$oScopeSearch = $oApp['scope_validator']->GetScopeFilterForProfiles(UserRights::ListProfiles(), $oSearch->GetClass(), UR_ACTION_READ);
$oSearch = ($oScopeSearch !== null) ? $oSearch->Intersect($oScopeSearch) : null;
// - Allowing all data if necessary
if ($oScopeSearch->IsAllDataAllowed())
{
$oSearch->AllowAllData();
}
if ($oSearch !== null)
{
$aLevelsProperties[$sCurrentLevelAlias] = array(
@@ -600,15 +561,7 @@ class BrowseBrickController extends BrickController
$aRow[$key]['fields'] = array();
foreach ($aLevelsProperties[$key]['fields'] as $aField)
{
$oAttDef = MetaModel::GetAttributeDef(get_class($value), $aField['code']);
if ($oAttDef->GetEditClass() === 'Duration')
{
$aRow[$key]['fields'][$aField['code']] = $oAttDef->GetAsHTML($value->Get($aField['code']));
}
else
{
$aRow[$key]['fields'][$aField['code']] = $oAttDef->GetValueLabel($value->Get($aField['code']));
}
$aRow[$key]['fields'][$aField['code']] = $value->Get($aField['code']);
}
}
}
@@ -677,3 +630,5 @@ class BrowseBrickController extends BrickController
}
}
?>

View File

@@ -37,17 +37,8 @@ class DefaultController
// Doing it only for tile visible on home page to avoid unnecessary rendering
if (($oBrick->GetVisibleHome() === true) && ($oBrick->GetTileControllerAction() !== null))
{
$aControllerActionParts = explode('::', $oBrick->GetTileControllerAction());
if (count($aControllerActionParts) !== 2)
{
$oApp->abort(500, 'Tile controller action must be of form "\Namespace\ControllerClass::FunctionName" for brick "' . $oBrick->GetId() . '"');
}
$sControllerName = $aControllerActionParts[0];
$sControllerAction = $aControllerActionParts[1];
$oController = new $sControllerName($oRequest, $oApp, $oBrick->GetId());
$aData['aTilesRendering'][$oBrick->GetId()] = $oController->$sControllerAction($oRequest, $oApp, $oBrick->GetId());
$oController = new \Combodo\iTop\Portal\Controller\ManageBrickController($oRequest, $oApp);
$aData['aTilesRendering'][$oBrick->GetId()] = $oController->HomeAction($oRequest, $oApp);
}
}

View File

@@ -28,8 +28,6 @@ use \MetaModel;
use \AttributeDefinition;
use \AttributeDate;
use \AttributeDateTime;
use \AttributeDuration;
use \AttributeSubItem;
use \DBSearch;
use \DBObjectSearch;
use \DBObjectSet;
@@ -61,15 +59,6 @@ class ManageBrickController extends BrickController
// Getting search value
$sSearchValue = $oRequest->get('sSearchValue', null);
// Getting area columns properties
$aColumnsAttrs = $oBrick->GetFields();
// Adding friendlyname attribute to the list is not already in it
$sTitleAttrCode = 'friendlyname';
if (($sTitleAttrCode !== null) && !in_array($sTitleAttrCode, $aColumnsAttrs))
{
$aColumnsAttrs = array_merge(array($sTitleAttrCode), $aColumnsAttrs);
}
// Starting to build query
$oQuery = DBSearch::FromOQL($oBrick->GetOql());
@@ -209,11 +198,6 @@ class ManageBrickController extends BrickController
if ($oDistinctScopeQuery != null)
{
$oDistinctQuery = $oDistinctQuery->Intersect($oDistinctScopeQuery);
// - Allowing all data if necessary
if ($oDistinctScopeQuery->IsAllDataAllowed())
{
$oDistinctQuery->AllowAllData();
}
}
// Adding grouping conditions
$oFieldExp = new FieldExpression($sGroupingAreaAttCode, $sParentAlias);
@@ -268,19 +252,7 @@ class ManageBrickController extends BrickController
// Note : Will need to moved the scope restriction on queries elsewhere when we consider grouping on something else than finalclass
// Note : We now get view scope instead of edit scope as we allowed users to view/edit objects in the brick regarding their rights
$oScopeQuery = $oApp['scope_validator']->GetScopeFilterForProfiles(UserRights::ListProfiles(), $aGroupingAreasValue['value'], UR_ACTION_READ);
if ($oScopeQuery !== null)
{
$oAreaQuery = $oAreaQuery->Intersect($oScopeQuery);
// - Allowing all data if necessary
if ($oScopeQuery->IsAllDataAllowed())
{
$oAreaQuery->AllowAllData();
}
}
else
{
$oAreaQuery = null;
}
$oAreaQuery = ($oScopeQuery !== null) ? $oAreaQuery->Intersect($oScopeQuery) : null;
$aQueries[$sKey] = $oAreaQuery;
}
@@ -292,7 +264,6 @@ class ManageBrickController extends BrickController
// - Check how many records there is.
// - Update $sDataLoading with its new value regarding the number of record and the threshold
$oCountSet = new DBObjectSet($oQuery);
$oCountSet->OptimizeColumnLoad(array());
$fThreshold = (float) MetaModel::GetModuleSetting($oApp['combodo.portal.instance.id'], 'lazy_loading_threshold');
$sDataLoading = ($oCountSet->Count() > $fThreshold) ? AbstractBrick::ENUM_DATA_LOADING_LAZY : AbstractBrick::ENUM_DATA_LOADING_FULL;
unset($oCountSet);
@@ -314,7 +285,6 @@ class ManageBrickController extends BrickController
// Getting total records number
$oCountSet = new DBObjectSet($oQuery);
$oCountSet->OptimizeColumnLoad(array($oQuery->GetClassAlias() => $aColumnsAttrs));
$aData['recordsTotal'] = $oCountSet->Count();
$aData['recordsFiltered'] = $oCountSet->Count();
unset($oCountSet);
@@ -326,8 +296,6 @@ class ManageBrickController extends BrickController
{
$oSet = new DBObjectSet($oQuery);
}
$oSet->OptimizeColumnLoad(array($oQuery->GetClassAlias() => $aColumnsAttrs));
$oSet->SetOrderByClasses();
$aSets[$sKey] = $oSet;
}
}
@@ -338,7 +306,15 @@ class ManageBrickController extends BrickController
{
// Set properties
$sCurrentClass = $sKey;
$sTitleAttrCode = MetaModel::GetFriendlyNameAttributeCode($sCurrentClass);
// Getting area columns properties
$aColumnsAttrs = $oBrick->GetFields();
// Adding friendlyname attribute to the list is not already in it
if (($sTitleAttrCode !== null) && !in_array($sTitleAttrCode, $aColumnsAttrs))
{
$aColumnsAttrs = array_merge(array($sTitleAttrCode), $aColumnsAttrs);
}
// Defining which attribute will open the edition form)
$sMainActionAttrCode = $aColumnsAttrs[0];
@@ -391,7 +367,7 @@ class ManageBrickController extends BrickController
);
}
}
$oAttDef = MetaModel::GetAttributeDef($sCurrentClass, $sItemAttr);
if ($oAttDef->IsExternalKey())
{
@@ -411,10 +387,6 @@ class ManageBrickController extends BrickController
}
}
}
elseif ($oAttDef instanceof AttributeSubItem || $oAttDef instanceof AttributeDuration)
{
$sValue = $oAttDef->GetAsHTML($oCurrentRow->Get($sItemAttr));
}
else
{
$sValue = $oAttDef->GetValueLabel($oCurrentRow->Get($sItemAttr));
@@ -474,3 +446,5 @@ class ManageBrickController extends BrickController
}
}
?>

View File

@@ -32,7 +32,6 @@ use \IssueLog;
use \MetaModel;
use \DBSearch;
use \DBObjectSearch;
use \FalseExpression;
use \BinaryExpression;
use \FieldExpression;
use \VariableExpression;
@@ -40,8 +39,6 @@ use \ListExpression;
use \ScalarExpression;
use \DBObjectSet;
use \cmdbAbstractObject;
use \AttributeEnum;
use \AttributeFinalClass;
use \UserRights;
use \Combodo\iTop\Portal\Helper\ApplicationHelper;
use \Combodo\iTop\Portal\Helper\SecurityHelper;
@@ -86,7 +83,7 @@ class ObjectController extends AbstractController
}
// Retrieving object
$oObject = MetaModel::GetObject($sObjectClass, $sObjectId, false /* MustBeFound */, $oApp['scope_validator']->IsAllDataAllowedForScope(UserRights::ListProfiles(), $sObjectClass));
$oObject = MetaModel::GetObject($sObjectClass, $sObjectId, false /* MustBeFound */);
if ($oObject === null)
{
// We should never be there as the secuirty helper makes sure that the object exists, but just in case.
@@ -158,7 +155,7 @@ class ObjectController extends AbstractController
}
// Retrieving object
$oObject = MetaModel::GetObject($sObjectClass, $sObjectId, false /* MustBeFound */, $oApp['scope_validator']->IsAllDataAllowedForScope(UserRights::ListProfiles(), $sObjectClass));
$oObject = MetaModel::GetObject($sObjectClass, $sObjectId, false /* MustBeFound */);
if ($oObject === null)
{
// We should never be there as the secuirty helper makes sure that the object exists, but just in case.
@@ -278,26 +275,23 @@ class ObjectController extends AbstractController
}
// Retrieving origin object
// Note : AllowAllData set to true here instead of checking scope's flag because we are displaying a value that has been set and validated
$oOriginObject = MetaModel::GetObject($sObjectClass, $sObjectId, true, true);
$oOriginObject = MetaModel::GetObject($sObjectClass, $sObjectId);
// Retrieving target object (We check if the method is a simple function or if it's part of a class in which case only static function are supported)
if (!strpos($sMethodName, '::'))
{
$oTargetObject = $sMethodName($oOriginObject);
$sTargetObject = $sMethodName($oOriginObject);
}
else
{
$aMethodNameParts = explode('::', $sMethodName);
$sMethodClass = $aMethodNameParts[0];
$sMethodName = $aMethodNameParts[1];
$oTargetObject = $sMethodClass::$sMethodName($oOriginObject);
$sTargetObject = $aMethodNameParts[0]::$aMethodNameParts[1]($oOriginObject);
}
// Preparing redirection
// - Route
$aRouteParams = array(
'sObjectClass' => get_class($oTargetObject)
'sObjectClass' => get_class($sTargetObject)
);
$sRedirectRoute = $oApp['url_generator']->generate('p_object_create', $aRouteParams);
// - Request
@@ -333,7 +327,7 @@ class ObjectController extends AbstractController
// }
// Retrieving object
$oObject = MetaModel::GetObject($sObjectClass, $sObjectId, false /* MustBeFound */, $oApp['scope_validator']->IsAllDataAllowedForScope(UserRights::ListProfiles(), $sObjectClass));
$oObject = MetaModel::GetObject($sObjectClass, $sObjectId, false /* MustBeFound */);
if ($oObject === null)
{
// We should never be there as the secuirty helper makes sure that the object exists, but just in case.
@@ -341,9 +335,6 @@ class ObjectController extends AbstractController
$oApp->abort(404, Dict::S('UI:ObjectDoesNotExist'));
}
// Retrieving request parameters
$sOperation = $oRequest->request->get('operation');
// Preparing a dedicated form for the stimulus application
$aFormProperties = array(
'id' => 'apply-stimulus',
@@ -381,39 +372,14 @@ class ObjectController extends AbstractController
'url' => $oApp['url_generator']->generate('p_object_edit', array('sObjectClass' => $sObjectClass, 'sObjectId' => $sObjectId))
);
// TODO : This is a ugly patch to avoid showing a modal with a readonly form to the user as it would prevent user from finishing the transition.
// Instead, we apply the stimulus directly here and then go to the edited object.
if ($sOperation === null)
{
if (isset($aData['form']['editable_fields_count']) && $aData['form']['editable_fields_count'] === 0)
{
$sOperation = 'redirect';
$oSubRequest = $oRequest;
$oSubRequest->request->set('operation', 'submit');
$oSubRequest->request->set('stimulus_code', null);
$aData = array('sMode' => 'apply_stimulus');
$aData['form'] = $this->HandleForm($oSubRequest, $oApp, $aData['sMode'], $sObjectClass, $sObjectId, $aFormProperties);
// Redefining the array to be as simple as possible :
$aData = array('redirection' =>
array('url' => $oApp['url_generator']->generate('p_object_edit', array('sObjectClass' => $sObjectClass, 'sObjectId' => $sObjectId)))
);
}
}
// Preparing response
if ($oRequest->isXmlHttpRequest())
{
// We have to check whether the 'operation' parameter is defined or not in order to know if the form is required via ajax (to be displayed as a modal dialog) or if it's a lifecycle call from a existing form.
if ($sOperation === null)
if ($oRequest->request->get('operation') === null)
{
$oResponse = $oApp['twig']->render('itop-portal-base/portal/src/views/bricks/object/modal.html.twig', $aData);
}
elseif ($sOperation === 'redirect')
{
$oResponse = $oApp['twig']->render('itop-portal-base/portal/src/views/modal/mode_loader.html.twig', $aData);
}
else
{
$oResponse = $oApp->json($aData);
@@ -462,7 +428,7 @@ class ObjectController extends AbstractController
}
else
{
$oObject = MetaModel::GetObject($sObjectClass, $sObjectId, true, $oApp['scope_validator']->IsAllDataAllowedForScope(UserRights::ListProfiles(), $sObjectClass));
$oObject = MetaModel::GetObject($sObjectClass, $sObjectId);
}
// Preparing transitions only if we are currently going through one
@@ -507,16 +473,9 @@ class ObjectController extends AbstractController
->SetMode($sMode)
->SetActionRulesToken($sActionRulesToken)
->SetRenderer($oFormRenderer)
->SetFormProperties($aFormProperties);
if ($sMode === 'apply_stimulus')
{
$aEditFormProperties = ApplicationHelper::GetLoadedFormFromClass($oApp, $sObjectClass, ObjectFormManager::ENUM_MODE_APPLY_STIMULUS);
$oFormManager->MergeFormProperties($aEditFormProperties);
}
$oFormManager->Build();
->SetFormProperties($aFormProperties)
->Build();
// Check the number of editable fields
$aFormData['editable_fields_count'] = $oFormManager->GetForm()->GetEditableFieldCount();
}
@@ -654,8 +613,6 @@ class ObjectController extends AbstractController
// Retrieving parameters
$sQuery = $aRequestContent['sQuery'];
$sFormPath = $aRequestContent['sFormPath'];
$sFieldId = $aRequestContent['sFieldId'];
// Checking security layers
if (!SecurityHelper::IsActionAllowed($oApp, UR_ACTION_READ, $sHostObjectClass, $sHostObjectId))
@@ -667,8 +624,7 @@ class ObjectController extends AbstractController
// Retrieving host object for future DBSearch parameters
if ($sHostObjectId !== null)
{
// Note : AllowAllData set to true here instead of checking scope's flag because we are displaying a value that has been set and validated
$oHostObject = MetaModel::GetObject($sHostObjectClass, $sHostObjectId, true, true);
$oHostObject = MetaModel::GetObject($sHostObjectClass, $sHostObjectId);
}
else
{
@@ -709,58 +665,20 @@ class ObjectController extends AbstractController
// Building search query
// - Retrieving target object class from attcode
$oTargetAttDef = MetaModel::GetAttributeDef($sHostObjectClass, $sTargetAttCode);
if ($oTargetAttDef->GetEditClass() === 'CustomFields')
{
$oRequestTemplate = $oHostObject->Get($sTargetAttCode);
$oTemplateFieldSearch = $oRequestTemplate->GetForm()->GetField('user_data')->GetForm()->GetField($sFieldId)->GetSearch();
$sTargetObjectClass = $oTemplateFieldSearch->GetClass();
}
elseif ($oTargetAttDef->IsLinkSet())
{
throw new Exception('Search autocomplete cannot apply on AttributeLinkedSet objects, ' . get_class($oTargetAttDef) . ' (' . $sHostObjectClass . '->' . $sTargetAttCode . ') given.');
}
else
{
$sTargetObjectClass = $oTargetAttDef->GetTargetClass();
}
$sTargetObjectClass = $oTargetAttDef->GetTargetClass();
// - Base query from meta model
if ($oTargetAttDef->GetEditClass() === 'CustomFields')
{
$oSearch = $oTemplateFieldSearch;
}
else
{
$oSearch = DBSearch::FromOQL($oTargetAttDef->GetValuesDef()->GetFilterExpression());
}
$oSearch = DBSearch::FromOQL($oTargetAttDef->GetValuesDef()->GetFilterExpression());
// - Adding query condition
$oSearch->AddConditionExpression(new BinaryExpression(new FieldExpression('friendlyname', $oSearch->GetClassAlias()), 'LIKE', new VariableExpression('ac_query')));
// - Intersecting with scope constraints
// Note : This do NOT apply to custom fields as the portal administrator is not supposed to know which objects will be put in the templates.
// It is the responsability of the template designer to write the right query so the user see only what he should.
if ($oTargetAttDef->GetEditClass() !== 'CustomFields')
{
$oScopeSearch = $oApp['scope_validator']->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sTargetObjectClass, UR_ACTION_READ);
$oSearch = $oSearch->Intersect($oScopeSearch);
// - Allowing all data if necessary
if ($oScopeSearch->IsAllDataAllowed())
{
$oSearch->AllowAllData();
}
}
$oSearch = $oSearch->Intersect($oApp['scope_validator']->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sTargetObjectClass, UR_ACTION_READ));
// Retrieving results
// - Preparing object set
$oSet = new DBObjectSet($oSearch, array(), array('this' => $oHostObject, 'ac_query' => '%' . $sQuery . '%'));
$oSet->OptimizeColumnLoad(array($oSearch->GetClassAlias() => array('friendlyname')));
// Note : This limit is also used in the field renderer by typeahead to determine how many suggestions to display
if ($oTargetAttDef->GetEditClass() === 'CustomFields')
{
$oSet->SetLimit(static::DEFAULT_COUNT_PER_PAGE_LIST);
}
else
{
$oSet->SetLimit($oTargetAttDef->GetMaximumComboLength()); // TODO : Is this the right limit value ? We might want to use another parameter
}
$oSet->SetLimit($oTargetAttDef->GetMaximumComboLength()); // TODO : Is this the right limit value ? We might want to use another parameter
// - Retrieving objects
while ($oItem = $oSet->Fetch())
{
@@ -811,8 +729,7 @@ class ObjectController extends AbstractController
// Retrieving host object for future DBSearch parameters
if ($sHostObjectId !== null)
{
// Note : AllowAllData set to true here instead of checking scope's flag because we are displaying a value that has been set and validated
$oHostObject = MetaModel::GetObject($sHostObjectClass, $sHostObjectId, true, true);
$oHostObject = MetaModel::GetObject($sHostObjectClass, $sHostObjectId);
}
else
{
@@ -878,12 +795,6 @@ class ObjectController extends AbstractController
$sTargetObjectClass = $oRemoteAttDef->GetTargetClass();
}
}
elseif ($oTargetAttDef->GetEditClass() === 'CustomFields')
{
$oRequestTemplate = $oHostObject->Get($sTargetAttCode);
$oTemplateFieldSearch = $oRequestTemplate->GetForm()->GetField('user_data')->GetForm()->GetField($sFieldId)->GetSearch();
$sTargetObjectClass = $oTemplateFieldSearch->GetClass();
}
else
{
throw new Exception('Search from attribute can only apply on AttributeExternalKey or AttributeLinkedSet objects, ' . get_class($oTargetAttDef) . ' given.');
@@ -892,18 +803,16 @@ class ObjectController extends AbstractController
// - Retrieving class attribute list
$aAttCodes = ApplicationHelper::GetLoadedListFromClass($oApp, $sTargetObjectClass, 'list');
// - Adding friendlyname attribute to the list is not already in it
$sTitleAttCode = 'friendlyname';
$sTitleAttCode = MetaModel::GetFriendlyNameAttributeCode($sTargetObjectClass);
if (($sTitleAttCode !== null) && !in_array($sTitleAttCode, $aAttCodes))
{
$aAttCodes = array_merge(array($sTitleAttCode), $aAttCodes);
}
// - Retrieving scope search
// Note : This do NOT apply to custom fields as the portal administrator is not supposed to know which objects will be put in the templates.
// It is the responsability of the template designer to write the right query so the user see only what he should.
$oScopeSearch = $oApp['scope_validator']->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sTargetObjectClass, UR_ACTION_READ);
$aInternalParams = array();
if (($oScopeSearch === null) && ($oTargetAttDef->GetEditClass() !== 'CustomFields'))
if ($oScopeSearch === null)
{
IssueLog::Info(__METHOD__ . ' at line ' . __LINE__ . ' : User #' . UserRights::GetUserId() . ' has no scope query for ' . $sTargetObjectClass . ' class.');
$oApp->abort(404, Dict::S('UI:ObjectDoesNotExist'));
@@ -918,11 +827,6 @@ class ObjectController extends AbstractController
{
$oSearch = $oScopeSearch;
}
elseif ($oTargetAttDef->GetEditClass() === 'CustomFields')
{
// Note : $oTemplateFieldSearch has been defined in the "Retrieving target object class from attcode" part, it is not available otherwise
$oSearch = $oTemplateFieldSearch;
}
// - Filtering objects to ignore
if (($aObjectIdsToIgnore !== null) && (is_array($aObjectIdsToIgnore)))
@@ -935,7 +839,7 @@ class ObjectController extends AbstractController
}
$oSearch->AddConditionExpression(new BinaryExpression(new FieldExpression('id', $oSearch->GetClassAlias()), 'NOT IN', new ListExpression($aExpressions)));
}
// - Adding query condition
$aInternalParams['this'] = $oHostObject;
if ($sQuery !== null)
@@ -947,35 +851,7 @@ class ObjectController extends AbstractController
$oAttDef = MetaModel::GetAttributeDef($sTargetObjectClass, $aAttCodes[$i]);
$sAttCode = (!$oAttDef->IsExternalKey()) ? $aAttCodes[$i] : $aAttCodes[$i] . '_friendlyname';
// Building expression for the current attcode
// - For attributes that need conversion from their display value to storage value
// Note : This is dirty hack that will need to be refactored in the OQL core in order to be nicer and to be extended to other types such as dates etc...
if (($oAttDef instanceof AttributeEnum) || ($oAttDef instanceof AttributeFinalClass))
{
// Looking up storage value
$aMatchedCodes = array();
foreach ($oAttDef->GetAllowedValues() as $sValueCode => $sValueLabel)
{
if (stripos($sValueLabel, $sQuery) !== false)
{
$aMatchedCodes[] = $sValueCode;
}
}
// Building expression
if (!empty($aMatchedCodes))
{
$oEnumeratedListExpr = ListExpression::FromScalars($aMatchedCodes);
$oBinExpr = new BinaryExpression(new FieldExpression($sAttCode, $oSearch->GetClassAlias()), 'IN', $oEnumeratedListExpr);
}
else
{
$oBinExpr = new FalseExpression();
}
}
// - For regular attributs
else
{
$oBinExpr = new BinaryExpression(new FieldExpression($sAttCode, $oSearch->GetClassAlias()), 'LIKE', new VariableExpression('re_query'));
}
$oBinExpr = new BinaryExpression(new FieldExpression($sAttCode, $oSearch->GetClassAlias()), 'LIKE', new VariableExpression('re_query'));
// Adding expression to the full expression (all attcodes)
if ($i === 0)
{
@@ -992,17 +868,7 @@ class ObjectController extends AbstractController
}
// - Intersecting with scope constraints
// Note : This do NOT apply to custom fields as the portal administrator is not supposed to know which objects will be put in the templates.
// It is the responsability of the template designer to write the right query so the user see only what he should.
if (($oScopeSearch !== null) && ($oTargetAttDef->GetEditClass() !== 'CustomFields'))
{
$oSearch = $oSearch->Intersect($oScopeSearch);
// - Allowing all data if necessary
if ($oScopeSearch->IsAllDataAllowed())
{
$oSearch->AllowAllData();
}
}
$oSearch = $oSearch->Intersect($oScopeSearch);
// Retrieving results
// - Preparing object set
@@ -1080,7 +946,7 @@ class ObjectController extends AbstractController
'sFormManagerData' => $sFormManagerData
)
);
if ($oRequest->isXmlHttpRequest())
{
$oResponse = $oApp['twig']->render('itop-portal-base/portal/src/views/bricks/object/modal.html.twig', $aData);
@@ -1135,8 +1001,7 @@ class ObjectController extends AbstractController
// Retrieving host object for future DBSearch parameters
if ($sHostObjectId !== null)
{
// Note : AllowAllData set to true here instead of checking scope's flag because we are displaying a value that has been set and validated
$oHostObject = MetaModel::GetObject($sHostObjectClass, $sHostObjectId, true, true);
$oHostObject = MetaModel::GetObject($sHostObjectClass, $sHostObjectId);
}
else
{
@@ -1176,7 +1041,7 @@ class ObjectController extends AbstractController
// // - Retrieving class attribute list
// $aAttCodes = MetaModel::FlattenZList(MetaModel::GetZListItems($sTargetObjectClass, 'list'));
// // - Adding friendlyname attribute to the list is not already in it
// $sTitleAttrCode = 'friendlyname';
// $sTitleAttrCode = MetaModel::GetFriendlyNameAttributeCode($sTargetObjectClass);
// if (($sTitleAttrCode !== null) && !in_array($sTitleAttrCode, $aAttCodes))
// {
// $aAttCodes = array_merge(array($sTitleAttrCode), $aAttCodes);
@@ -1227,11 +1092,6 @@ class ObjectController extends AbstractController
// }
// - Intersecting with scope constraints
$oSearch = $oSearch->Intersect($oScopeSearch);
// - Allowing all data if necessary
if ($oScopeSearch->IsAllDataAllowed())
{
$oSearch->AllowAllData();
}
// Retrieving results
// - Preparing object set
@@ -1386,8 +1246,7 @@ class ObjectController extends AbstractController
}
}
// Note : The Content-Type header is set to 'text/plain' in order to be IE9 compatible. Otherwise ('application/json') IE9 will download the response as a JSON file to the user computer...
$oResponse = $oApp->json($aData, 200, array('Content-Type' => 'text/plain'));
$oResponse = $oApp->json($aData);
break;
case 'download':
@@ -1448,12 +1307,7 @@ class ObjectController extends AbstractController
}
// Building the search
$bIgnoreSilos = $oApp['scope_validator']->IsAllDataAllowedForScope(UserRights::ListProfiles(), $sObjectClass);
$oSearch = DBObjectSearch::FromOQL("SELECT " . $sObjectClass . " WHERE id IN ('" . implode("','", $aObjectIds) . "')");
if ($bIgnoreSilos === true)
{
$oSearch->AllowAllData();
}
$oSet = new DBObjectSet($oSearch);
$oSet->OptimizeColumnLoad($aObjectAttCodes);

View File

@@ -493,9 +493,6 @@ abstract class PortalBrick extends AbstractBrick
$this->SetDecorationClassNavigationMenu($optionalNodeValue);
}
break;
case 'tile_controller_action':
$this->SetTileControllerAction($oBrickSubNode->GetText(static::DEFAULT_TILE_CONTROLLER_ACTION));
break;
}
}

View File

@@ -29,7 +29,6 @@ use \MetaModel;
use \CMDBSource;
use \DBObject;
use \DBObjectSet;
use \DBSearch;
use \DBObjectSearch;
use \DBObjectSetComparator;
use \InlineImage;
@@ -50,7 +49,6 @@ class ObjectFormManager extends FormManager
const ENUM_MODE_VIEW = 'view';
const ENUM_MODE_EDIT = 'edit';
const ENUM_MODE_CREATE = 'create';
const ENUM_MODE_APPLY_STIMULUS = 'apply_stimulus';
protected $oApp;
protected $oObject;
@@ -94,8 +92,7 @@ class ObjectFormManager extends FormManager
}
else
{
// Note : AllowAllData set to true here instead of checking scope's flag because we are displaying a value that has been set and validated
$oObject = MetaModel::GetObject($sObjectClass, $aJson['formobject_id'], true, true);
$oObject = MetaModel::GetObject($sObjectClass, $aJson['formobject_id'], true);
}
$oFormManager->SetObject($oObject);
@@ -485,18 +482,6 @@ class ObjectFormManager extends FormManager
{
$oField->SetReadOnly(true);
}
// - Else if it's must change, we force it as not readonly and not hidden
elseif (($iFieldFlags & OPT_ATT_MUSTCHANGE) === OPT_ATT_MUSTCHANGE)
{
$oField->SetReadOnly(false);
$oField->SetHidden(false);
}
// - Else if it's must prompt, we force it as not readonly and not hidden
elseif (($iFieldFlags & OPT_ATT_MUSTPROMPT) === OPT_ATT_MUSTPROMPT)
{
$oField->SetReadOnly(false);
$oField->SetHidden(false);
}
else
{
// Normal field
@@ -531,61 +516,6 @@ class ObjectFormManager extends FormManager
$oField->SetInformationEndpoint($this->oApp['url_generator']->generate('p_object_get_informations_json'));
}
}
// - Field that require to apply scope on its DM OQL
if (in_array(get_class($oField), array('Combodo\\iTop\\Form\\Field\\SelectObjectField')))
{
if ($this->oApp !== null)
{
$oScopeOriginal = ($oField->GetSearch() !== null) ? $oField->GetSearch() : DBSearch::FromOQL($oAttDef->GetValuesDef()->GetFilterExpression());
$oScopeSearch = $this->oApp['scope_validator']->GetScopeFilterForProfiles(UserRights::ListProfiles(), $oScopeOriginal->GetClass(), UR_ACTION_READ);
if ($oScopeSearch === null)
{
IssueLog::Info(__METHOD__ . ' at line ' . __LINE__ . ' : User #' . UserRights::GetUserId() . ' has no scope query for ' . $oScopeOriginal->GetClass() . ' class.');
$this->oApp->abort(404, Dict::S('UI:ObjectDoesNotExist'));
}
$oScopeOriginal = $oScopeOriginal->Intersect($oScopeSearch);
// Note : This is to skip the silo restriction on the final query
if ($oScopeSearch->IsAllDataAllowed())
{
$oScopeOriginal->AllowAllData();
}
$oScopeOriginal->SetInternalParams(array('this' => $this->oObject));
$oField->SetSearch($oScopeOriginal);
}
}
// - Field that require processing on their subfields
if (in_array(get_class($oField), array('Combodo\\iTop\\Form\\Field\\SubFormField')))
{
$oSubForm = $oField->GetForm();
if ($oAttDef->GetEditClass() === 'CustomFields')
{
// Retrieving only user data fields (not the metadata fields of the template)
if ($oSubForm->HasField('user_data'))
{
$oUserDataField = $oSubForm->GetField('user_data');
$oUserDataForm = $oUserDataField->GetForm();
foreach ($oUserDataForm->GetFields() as $oCustomField)
{
// - Field that require a search endpoint (OQL based dropdown list fields)
if (in_array(get_class($oCustomField), array('Combodo\\iTop\\Form\\Field\\SelectObjectField')))
{
if ($this->oApp !== null)
{
$sSearchEndpoint = $this->oApp['url_generator']->generate('p_object_search_generic', array(
'sTargetAttCode' => $oAttDef->GetCode(),
'sHostObjectClass' => get_class($this->oObject),
'sHostObjectId' => ($this->oObject->IsNew()) ? null : $this->oObject->GetKey(),
'ar_token' => $this->GetActionRulesToken(),
));
$oCustomField->SetSearchEndpoint($sSearchEndpoint);
}
}
}
}
}
}
}
else
{
@@ -609,7 +539,7 @@ class ObjectFormManager extends FormManager
// Note : This snippet is inspired from AttributeLinkedSet::MakeFormField()
$aAttCodesToDisplay = ApplicationHelper::GetLoadedListFromClass($this->oApp, $oField->GetTargetClass(), 'list');
// - Adding friendlyname attribute to the list is not already in it
$sTitleAttCode = 'friendlyname';
$sTitleAttCode = MetaModel::GetFriendlyNameAttributeCode($oField->GetTargetClass());
if (($sTitleAttCode !== null) && !in_array($sTitleAttCode, $aAttCodesToDisplay))
{
$aAttCodesToDisplay = array_merge(array($sTitleAttCode), $aAttCodesToDisplay);
@@ -695,87 +625,6 @@ class ObjectFormManager extends FormManager
$this->oRenderer->SetForm($this->oForm);
}
/**
* Merging $this->aFormProperties with $aFormPropertiesToMerge. Merge only layout for now
*
* @param array $aFormPropertiesToMerge
* @throws Exception
*/
public function MergeFormProperties($aFormPropertiesToMerge)
{
if ($aFormPropertiesToMerge['layout'] !== null)
{
// Checking if we need to render the template from twig to html in order to parse the fields
if ($aFormPropertiesToMerge['layout']['type'] === 'twig')
{
// Creating sandbox twig env. to load and test the custom form template
$oTwig = new \Twig_Environment(new \Twig_Loader_String());
$sRendered = $oTwig->render($aFormPropertiesToMerge['layout']['content'], array('oRenderer' => $this->oRenderer, 'oObject' => $this->oObject));
}
else
{
$sRendered = $aFormPropertiesToMerge['layout']['content'];
}
// Parsing rendered template to find the fields
$oHtmlDocument = new \DOMDocument();
$oHtmlDocument->loadHTML('<root>' . $sRendered . '</root>');
// Adding fields to the list
$oXPath = new \DOMXPath($oHtmlDocument);
foreach ($oXPath->query('//div[@class="form_field"][@data-field-id]') as $oFieldNode)
{
$sFieldId = $oFieldNode->getAttribute('data-field-id');
$sFieldFlags = $oFieldNode->getAttribute('data-field-flags');
// $iFieldFlags = OPT_ATT_NORMAL;
// // Checking if field has form_path, if not, we add it
// if (!$oFieldNode->hasAttribute('data-form-path'))
// {
// $oFieldNode->setAttribute('data-form-path', $oForm->GetId());
// }
// Merging only fields that are already in the form
if (array_key_exists($sFieldId, $this->aFormProperties['fields']))
{
// Settings field flags from the data-field-flags attribute
foreach (explode(' ', $sFieldFlags) as $sFieldFlag)
{
if ($sFieldFlag !== '')
{
$sConst = 'OPT_ATT_' . strtoupper(str_replace('_', '', $sFieldFlag));
if (defined($sConst))
{
switch ($sConst)
{
case 'OPT_ATT_SLAVE':
case 'OPT_ATT_HIDDEN':
if (!array_key_exists($sFieldId, $this->aFormProperties['fields']))
{
$this->aFormProperties['fields'][$sFieldId] = array();
}
$this->aFormProperties['fields'][$sFieldId]['hidden'] = true;
break;
case 'OPT_ATT_READONLY':
if (!array_key_exists($sFieldId, $this->aFormProperties['fields']))
{
$this->aFormProperties['fields'][$sFieldId] = array();
}
$this->aFormProperties['fields'][$sFieldId]['read_only'] = true;
break;
}
}
else
{
IssueLog::Error(__METHOD__ . ' at line ' . __LINE__ . ' : Flag "' . $sFieldFlag . '" is not valid for field [@data-field-id="' . $sFieldId . '"] in form[@id="' . $aFormPropertiesToMerge['id'] . '"]');
throw new Exception('Flag "' . $sFieldFlag . '" is not valid for field [@data-field-id="' . $sFieldId . '"] in form[@id="' . $aFormPropertiesToMerge['id'] . '"]');
}
}
}
}
}
}
}
/**
* Calls all form fields OnCancel method in order to delegate them the cleanup;
*
@@ -942,8 +791,7 @@ class ObjectFormManager extends FormManager
// LinkedSet
if (!$oAttDef->IsIndirect())
{
// Note : AllowAllData set to true here instead of checking scope's flag because we are displaying a value that has been set and validated
$oLinkedObject = MetaModel::GetObject($sTargetClass, abs($iTargetId), true, true);
$oLinkedObject = MetaModel::GetObject($sTargetClass, abs($iTargetId));
$oValueSet->AddObject($oLinkedObject);
}
// LinkedSetIndirect
@@ -959,8 +807,7 @@ class ObjectFormManager extends FormManager
// Existing relation
else
{
// Note : AllowAllData set to true here instead of checking scope's flag because we are displaying a value that has been set and validated
$oLink = MetaModel::GetObject($sTargetClass, $iTargetId, true, true);
$oLink = MetaModel::GetObject($sTargetClass, $iTargetId);
}
$oValueSet->AddObject($oLink);
}
@@ -1013,7 +860,7 @@ class ObjectFormManager extends FormManager
else
{
$this->oObject->Set($sAttCode, $value);
}
}
}
}
$this->oObject->DoComputeValues();

View File

@@ -202,7 +202,6 @@ class ApplicationHelper
return Dict::S($sStringCode, $sDefault, $bUserLanguageOnly);
})
);
// A filter to format a string via the Dict::Format function
// Usage in twig : {{ 'String:ToTranslate'|dict_format() }}
$oApp['twig']->addFilter(new Twig_SimpleFilter('dict_format', function($sStringCode, $sParam01 = null, $sParam02 = null, $sParam03 = null, $sParam04 = null)
@@ -210,12 +209,10 @@ class ApplicationHelper
return Dict::Format($sStringCode, $sParam01, $sParam02, $sParam03, $sParam04);
})
);
// Filters to enable base64 encode/decode
// Usage in twig : {{ 'String to encode'|base64_encode }}
$oApp['twig']->addFilter(new Twig_SimpleFilter('base64_encode', 'base64_encode'));
$oApp['twig']->addFilter(new Twig_SimpleFilter('base64_decode', 'base64_decode'));
// Filters to enable json decode (encode already exists)
// Usage in twig : {{ aSomeArray|json_decode }}
$oApp['twig']->addFilter(new Twig_SimpleFilter('json_decode', function($sJsonString, $bAssoc = false)
@@ -223,21 +220,6 @@ class ApplicationHelper
return json_decode($sJsonString, $bAssoc);
})
);
// Filter to add itopversion to an url
$oApp['twig']->addFilter(new Twig_SimpleFilter('add_itop_version', function($sUrl)
{
if (strpos($sUrl, '?') === false)
{
$sUrl = $sUrl . "?itopversion=" . ITOP_VERSION;
}
else
{
$sUrl = $sUrl . "&itopversion=" . ITOP_VERSION;
}
return $sUrl;
}));
}
/**

View File

@@ -4,7 +4,7 @@
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
@@ -23,7 +23,6 @@ use \Exception;
use \Silex\Application;
use \DOMNodeList;
use \DOMFormatException;
use \UserRights;
use \DBObject;
use \DBSearch;
use \DBObjectSet;
@@ -43,7 +42,6 @@ class ContextManipulatorHelper
const ENUM_RULE_CALLBACK_OPEN_EDIT = 'edit';
const DEFAULT_RULE_CALLBACK_OPEN = self::ENUM_RULE_CALLBACK_OPEN_VIEW;
protected $oApp;
protected $aRules;
public function __construct()
@@ -61,7 +59,7 @@ class ContextManipulatorHelper
public function Init(DOMNodeList $oNodes)
{
$this->aRules = array();
// Iterating over the scope nodes
foreach ($oNodes as $oRuleNode)
{
@@ -183,11 +181,6 @@ class ContextManipulatorHelper
}
}
public function SetApp($oApp)
{
$this->oApp = $oApp;
}
/**
* Returns a hash array of rules
*
@@ -229,7 +222,7 @@ class ContextManipulatorHelper
* ...
* )
* )
*
*
* @param array $aData
* @param DBObject $oObject
*/
@@ -297,13 +290,6 @@ class ContextManipulatorHelper
}
}
// Checking for silos
$oScopeSearch = $this->oApp['scope_validator']->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sSearchClass, UR_ACTION_READ);
if ($oScopeSearch->IsAllDataAllowed())
{
$oSearch->AllowAllData();
}
// Retrieving source object(s) and applying rules
$oSet = new DBObjectSet($oSearch, array(), $aSearchParams);
while ($oSourceObject = $oSet->Fetch())

View File

@@ -36,7 +36,6 @@ class ScopeValidatorHelper
const ENUM_TYPE_ALLOW = 'allow';
const ENUM_TYPE_RESTRICT = 'restrict';
const DEFAULT_GENERATED_CLASS = 'PortalScopesValues';
const DEFAULT_IGNORE_SILOS = false;
protected $sCachePath;
protected $sFilename;
@@ -180,9 +179,6 @@ class ScopeValidatorHelper
// Retrieving the edit query
$oOqlEditNode = $oScopeNode->GetOptionalElement('oql_edit');
$sOqlEdit = ( ($oOqlEditNode !== null) && ($oOqlEditNode->GetText() !== null) ) ? $oOqlEditNode->GetText() : null;
// Retrieving ignore allowed org flag
$oIgnoreSilosNode = $oScopeNode->GetOptionalElement('ignore_silos');
$bIgnoreSilos = ( ($oIgnoreSilosNode !== null) && ($oIgnoreSilosNode->GetText() === 'true') ) ? true : static::DEFAULT_IGNORE_SILOS;
// Retrieving profiles for the scope
$oProfilesNode = $oScopeNode->GetOptionalElement('allowed_profiles');
@@ -225,20 +221,13 @@ class ScopeValidatorHelper
$oExistingFilter = DBSearch::FromOQL($aProfiles[$sMatrixPrefix . static::ENUM_MODE_READ][$sOqlViewType]);
$aFilters = array($oExistingFilter, $oViewFilter);
$oResFilter = new DBUnionSearch($aFilters);
// Applying ignore_silos flag on result filter if necessary (As the union will remove it if it is not on all sub-queries)
if ($aProfiles[$sMatrixPrefix . static::ENUM_MODE_READ]['ignore_silos'] === true)
{
$bIgnoreSilos = true;
}
}
else
{
$oResFilter = $oViewFilter;
}
$aProfiles[$sMatrixPrefix . static::ENUM_MODE_READ] = array(
$sOqlViewType => $oResFilter->ToOQL(),
'ignore_silos' => $bIgnoreSilos
$sOqlViewType => $oResFilter->ToOQL()
);
// - Edit query
if ($sOqlEdit !== null)
@@ -275,8 +264,7 @@ class ScopeValidatorHelper
$oResFilter = $oEditFilter;
}
$aProfiles[$sMatrixPrefix . static::ENUM_MODE_WRITE] = array(
$sOqlViewType => $oResFilter->ToOQL(),
'ignore_silos' => $bIgnoreSilos
$sOqlViewType => $oResFilter->ToOQL()
);
}
}
@@ -285,7 +273,7 @@ class ScopeValidatorHelper
$aProfileClasses[] = $sClass;
}
}
// Filling the array with missing classes from MetaModel, so we can have an inheritance principle on the scope
// For each class explicitly given in the scopes, we check if its child classes were also in the scope :
// If not, we add them with the same OQL
@@ -307,14 +295,10 @@ class ScopeValidatorHelper
$aTmpProfile = $aProfiles[$iProfileId . '_' . $sProfileClass . '_' . $sAction];
foreach ($aTmpProfile as $sType => $sOql)
{
// IF condition is just to skip the 'ignore_silos' flag
if (in_array($sType, array(static::ENUM_TYPE_ALLOW, static::ENUM_TYPE_RESTRICT)))
{
$oTmpFilter = DBSearch::FromOQL($sOql);
$oTmpFilter->ChangeClass($sChildClass);
$oTmpFilter = DBSearch::FromOQL($sOql);
$oTmpFilter->ChangeClass($sChildClass);
$aTmpProfile[$sType] = $oTmpFilter->ToOQL();
}
$aTmpProfile[$sType] = $oTmpFilter->ToOQL();
}
$aProfiles[$iProfileId . '_' . $sChildClass . '_' . $sAction] = $aTmpProfile;
@@ -487,7 +471,6 @@ class ScopeValidatorHelper
$oSearch = null;
$aAllowSearches = array();
$aRestrictSearches = array();
$bIgnoreSilos = static::DEFAULT_IGNORE_SILOS;
// Checking the default mode
if ($iAction === null)
@@ -515,11 +498,6 @@ class ScopeValidatorHelper
{
$aRestrictSearches[] = DBSearch::FromOQL($aProfileMatrix['restrict']);
}
// If a profile should ignore allowed org, we set it for all its queries no matter the profile
if (isset($aProfileMatrix['ignore_silos']) && $aProfileMatrix['ignore_silos'] === true)
{
$bIgnoreSilos = true;
}
}
}
@@ -536,47 +514,10 @@ class ScopeValidatorHelper
$oSearch = new DBUnionSearch($aAllowSearches);
$oSearch = $oSearch->RemoveDuplicateQueries();
}
if ($bIgnoreSilos === true)
{
$oSearch->AllowAllData();
}
return $oSearch;
}
/**
* Returns true if at least one of the $aProfiles has the ignore_silos flag set to true for the $sClass.
*
* @param array $aProfiles
* @param string $sClass
* @return boolean
*/
public function IsAllDataAllowedForScope($aProfiles, $sClass)
{
$bIgnoreSilos = false;
// Iterating on profiles to retrieving the different OQLs parts
foreach ($aProfiles as $sProfile)
{
// Retrieving matrix informtions
$iProfileId = $this->GetProfileIdFromProfileName($sProfile);
// Retrieving profile OQLs
$sScopeValuesClass = $this->sGeneratedClass;
$aProfileMatrix = $sScopeValuesClass::GetProfileScope($iProfileId, $sClass, static::ENUM_MODE_READ);
if ($aProfileMatrix !== null)
{
// If a profile should ignore allowed org, we set it for all its queries no matter the profile
if (isset($aProfileMatrix['ignore_silos']) && $aProfileMatrix['ignore_silos'] === true)
{
$bIgnoreSilos = true;
}
}
}
return $bIgnoreSilos;
}
/**
* Returns the profile id from a string being either a constant or its name.
*

View File

@@ -112,7 +112,7 @@ class SecurityHelper
// Checking if the cmdbAbstractObject exists if id is specified
if ($sObjectId !== null)
{
$oObject = MetaModel::GetObject($sObjectClass, $sObjectId, false /* MustBeFound */, $oApp['scope_validator']->IsAllDataAllowedForScope(UserRights::ListProfiles(), $sObjectClass));
$oObject = MetaModel::GetObject($sObjectClass, $sObjectId, false /* MustBeFound */);
if ($oObject === null)
{
if ($oApp['debug'])

View File

@@ -44,7 +44,6 @@ class UrlGenerator extends SymfonyUrlGenerator
*/
public function generate($name, $parameters = array(), $referenceType = SymfonyUrlGenerator::ABSOLUTE_PATH)
{
// Mandatory parameters
$sExecModule = utils::ReadParam('exec_module', '', false, 'string');
$sExecPage = utils::ReadParam('exec_page', '', false, 'string');
if ($sExecModule !== '' && $sExecPage !== '')
@@ -53,18 +52,6 @@ class UrlGenerator extends SymfonyUrlGenerator
$parameters['exec_page'] = $sExecPage;
}
// Optional parameters
$sEnvSwitch = utils::ReadParam('env_switch', '', false, 'string');
if ($sEnvSwitch !== '')
{
$parameters['env_switch'] = $sEnvSwitch;
}
$sDebug = utils::ReadParam('debug', '', false, 'string');
if ($sDebug !== '')
{
$parameters['debug'] = $sDebug;
}
return parent::generate($name, $parameters, $referenceType);
}

View File

@@ -38,7 +38,6 @@ class ContextManipulatorServiceProvider implements ServiceProviderInterface
$oApp->flush();
$oContextManipulatorHelper = new ContextManipulatorHelper();
$oContextManipulatorHelper->SetApp($oApp);
return $oContextManipulatorHelper;
});

View File

@@ -73,11 +73,11 @@
// For the same reason, tooltip widget is created in "drawCallback" instead of here.
if( (data.tooltip !== undefined) && (data.tooltip !== ''))
{
cellElem.html( $('<span></span>').attr('title', data.tooltip).attr('data-toggle', 'tooltip').html(data.name).prop('outerHTML') );
cellElem.html( $('<span></span>').attr('title', data.tooltip).attr('data-toggle', 'tooltip').text(data.name).prop('outerHTML') );
}
else
{
cellElem.html(data.name);
cellElem.text(data.name);
}
// Building actions
@@ -97,11 +97,11 @@
break;
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_CREATE_FROM_THIS') }}':
url = levelPrimaryAction.url.replace(/-objectClass-/, data.class).replace(/-objectId-/, data.id);
url = AddParameterToUrl(url, 'ar_token', data.action_rules_token[levelPrimaryAction.type]);
url = addParameterToUrl(url, 'ar_token', data.action_rules_token[levelPrimaryAction.type]);
cellElem.attr('data-toggle', 'modal').attr('data-target', '#modal-for-all').attr('href', url);
break;
default:
//console.log('Action "'+levelPrimaryAction.type+'" not implemented');
console.log('Action "'+levelPrimaryAction.type+'" not implemented');
break;
}
@@ -150,11 +150,11 @@
break;
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_CREATE_FROM_THIS') }}':
url = action.url.replace(/-objectClass-/, data.class).replace(/-objectId-/, data.id);
url = AddParameterToUrl(url, 'ar_token', data.action_rules_token[action.type]);
url = addParameterToUrl(url, 'ar_token', data.action_rules_token[action.type]);
actionElem.attr('data-toggle', 'modal').attr('data-target', '#modal-for-all').attr('href', url);
break;
default:
//console.log('Action "'+action.type+'" not implemented for secondary action');
console.log('Action "'+action.type+'" not implemented for secondary action');
break;
}
@@ -201,6 +201,7 @@
"type": "html",
"data": oLevelsProperties[sKey].alias+".fields."+oLevelsProperties[sKey].fields[i].code
});
console.log(oLevelsProperties[sKey].fields[i].visible);
}
}
}
@@ -239,7 +240,6 @@
"displayLength": {{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::DEFAULT_COUNT_PER_PAGE_LIST') }},
"dom": '<"row"<"col-sm-6"l><"col-sm-6"<f><"visible-xs"p>>>t<"row"<"col-sm-6"i><"col-sm-6"p>>',
"columns": getColumnsDefinition(),
"order": [],
"drawCallback": function(settings){
// Tooltip has to been created here, as the render callback only returns a string, not an object.
$(this).find('[data-toggle="tooltip"]').tooltip({container: 'body', html: true, trigger: 'hover', placement: 'right'}); // container option is necessary when in a table

View File

@@ -25,7 +25,7 @@
</div>
</div>
<div class="col-xs-8 col-sm-10 col-lg-11 text-right">
<label>{{ 'Portal:Datatables:Language:Search'|dict_s }}<input type="search" class="form-control input-sm" id="brick_search_field" placeholder="" aria-controls="brick_main_table" value="{{ sSearchValue }}"></label>
<label>Filtrer :<input type="search" class="form-control input-sm" id="brick_search_field" placeholder="" aria-controls="brick_main_table" value="{{ sSearchValue }}"></label>
</div>
</div>
<ul class="list-group" id="brick_content_tree" data-level-id="L">
@@ -223,11 +223,11 @@
break;
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_CREATE_FROM_THIS') }}':
url = levelPrimaryAction.url.replace(/-objectClass-/, item.class).replace(/-objectId-/, item.id);
url = AddParameterToUrl(url, 'ar_token', item.action_rules_token[levelPrimaryAction.type]);
url = addParameterToUrl(url, 'ar_token', item.action_rules_token[levelPrimaryAction.type]);
aElem.attr('data-toggle', 'modal').attr('data-target', '#modal-for-all').attr('href', url);
break;
default:
//console.log('Action "'+levelPrimaryAction.type+'" not implemented for primary action');
console.log('Action "'+levelPrimaryAction.type+'" not implemented for primary action');
break;
}
@@ -275,11 +275,11 @@
break;
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_CREATE_FROM_THIS') }}':
url = action.url.replace(/-objectClass-/, item.class).replace(/-objectId-/, item.id);
url = AddParameterToUrl(url, 'ar_token', item.action_rules_token[action.type]);
url = addParameterToUrl(url, 'ar_token', item.action_rules_token[action.type]);
actionElem.attr('data-toggle', 'modal').attr('data-target', '#modal-for-all').attr('href', url);
break;
default:
//console.log('Action "'+action.type+'" not implemented for secondary action');
console.log('Action "'+action.type+'" not implemented for secondary action');
break;
}

View File

@@ -17,35 +17,24 @@
{% endblock %}
{% block pMainContentHolder%}
{% set iTableCount = 0 %}
{% if aGroupingAreasData|length > 0 %}
{% for aAreaData in aGroupingAreasData %}
{% if aAreaData.iItemsCount > 0 %}
{% set iTableCount = iTableCount + 1 %}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{{ aAreaData.sTitle }}</h3>
</div>
<div class="panel-body">
{# We decided not to show empty tables anymore #}
{#
{% if aAreaData.iItemsCount > 0 %}
#}
<table id="table-{{ aAreaData.sId }}" class="table table-striped table-bordered responsive" width="100%"></table>
{#
{% else %}
<div class="text-center">
{{ 'Brick:Portal:Manage:Table:NoData'|dict_s }}
</div>
{% endif %}
#}
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{{ aAreaData.sTitle }}</h3>
</div>
{% endif %}
<div class="panel-body">
{% if aAreaData.iItemsCount > 0 %}
<table id="table-{{ aAreaData.sId }}" class="table table-striped table-bordered responsive" width="100%"></table>
{% else %}
<div class="text-center">
{{ 'Brick:Portal:Manage:Table:NoData'|dict_s }}
</div>
{% endif %}
</div>
</div>
{% endfor %}
{% endif %}
{% if iTableCount == 0 %}
{% else %}
<div class="panel panel-default">
<div class="panel-body">
<h3 class="text-center">{{ 'Brick:Portal:Manage:Table:NoData'|dict_s }}</h3>
@@ -80,12 +69,12 @@
{
var tableProperties = columnsProperties[tableName];
if(tableProperties === undefined && window.console)
if(tableProperties === undefined)
{
console.log('Could not retrieve columns properties for table "'+tableName+'"');
return false;
}
if(rawData[tableName] === undefined && window.console)
if(rawData[tableName] === undefined)
{
console.log('Could not retrieve data for table "'+tableName+'"');
return false;
@@ -114,7 +103,7 @@
// Preparing the cell data
cellElem = (itemActions.length > 0) ? $('<a></a>') : $('<span></span>');
cellElem.html(row.attributes[att_code].value);
cellElem.text(row.attributes[att_code].value);
// Building actions
if(itemActions.length > 0)
{
@@ -131,7 +120,7 @@
cellElem.attr('data-toggle', 'modal').attr('data-target', '#modal-for-all').attr('href', url);
break;
default:
//console.log('Action "'+itemPrimaryAction+'" not implemented');
console.log('Action "'+itemPrimaryAction+'" not implemented');
break;
}
@@ -238,7 +227,7 @@
// Note : The '.off()' call is to unbind event from DataTables that where triggered before we could intercept anything
$('#table-{{ sAreaId }}_filter input').off().on('keyup', function(){
var me = this;
console.log('here');
clearTimeout(oKeyTimeout);
oKeyTimeout = setTimeout(function() {
oTable{{ sAreaId }}.search(me.value.latinise()).draw();

View File

@@ -24,7 +24,7 @@
{% if form.buttons is defined and form.buttons.transitions is defined and form.buttons.transitions|length > 0 %}
<div class="form_btn_transitions">
{% for sStimulusCode, sStimulusLabel in form.buttons.transitions %}
<button class="btn btn-primary form_btn_transition" type="submit" name="stimulus_code" value="{{ sStimulusCode }}">{{ sStimulusLabel }}</button>
<button class="btn btn-default form_btn_transition" type="submit" name="stimulus_code" value="{{ sStimulusCode }}">{{ sStimulusLabel }}</button>
{% endfor %}
</div>
{% endif %}
@@ -67,63 +67,60 @@
// Sticky buttons handler
{% if sMode != 'view' %}
if( $('#{{ sFormId }} .form_btn_regular button').length > 0 )
// Note : This pattern if to prevent performance issues
// - Cloning buttons
var oNormalRegularButtons_{{ sFormIdSanitized }} = $('#{{ sFormId }} .form_btn_regular');
var oStickyRegularButtons_{{ sFormIdSanitized }} = oNormalRegularButtons_{{ sFormIdSanitized }}.clone(true, true);
oStickyRegularButtons_{{ sFormIdSanitized }}.addClass('sticky');
if(oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_submit span.glyphicon').length > 0)
{
// Note : This pattern if to prevent performance issues
// - Cloning buttons
var oNormalRegularButtons_{{ sFormIdSanitized }} = $('#{{ sFormId }} .form_btn_regular');
var oStickyRegularButtons_{{ sFormIdSanitized }} = oNormalRegularButtons_{{ sFormIdSanitized }}.clone(true, true);
oStickyRegularButtons_{{ sFormIdSanitized }}.addClass('sticky');
if(oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_submit span.glyphicon').length > 0)
{
oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_submit').html( oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_submit span.glyphicon')[0].outerHTML );
}
if(oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_cancel span.glyphicon').length > 0)
{
oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_cancel').html( oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_cancel span.glyphicon')[0].outerHTML );
}
$('#{{ sFormId }}').closest({% if tIsModal == true %}'.modal'{% else %}'#main-content'{% endif %}).append(oStickyRegularButtons_{{ sFormIdSanitized }});
// - Global timeout for any
var oScrollTimeout;
// - Scroll handler
scrollHandler_{{ sFormIdSanitized }} = function () {
if($('#{{ sFormId }} .form_buttons').visible())
{
oStickyRegularButtons_{{ sFormIdSanitized }}.addClass('closed');
}
else
{
oStickyRegularButtons_{{ sFormIdSanitized }}.removeClass('closed');
}
};
// - Event binding for scroll
$({% if tIsModal == true %}'.modal.in'{% else %}window{% endif %}).off('scroll').on('scroll', function () {
if (oScrollTimeout) {
// Clear the timeout, if one is pending
clearTimeout(oScrollTimeout);
oScrollTimeout = null;
}
oScrollTimeout = setTimeout(scrollHandler_{{ sFormIdSanitized }}, 50);
});
// - Event binding for linkedset collapse
$({% if tIsModal == true %}'.modal.in'{% else %}window{% endif %}).off('shown.bs.collapse hidden.bs.collapse').on('shown.bs.collapse hidden.bs.collapse', function () {
scrollHandler_{{ sFormIdSanitized }}();
});
// - Event binding for form building / updating
// Note : We do not want to 'off' the event or it will remove listeners from the widget
oFieldSet_{{ sFormIdSanitized }}.on('form_built', function(oEvent){
scrollHandler_{{ sFormIdSanitized }}();
});
// - Initial test
setTimeout(function(){ scrollHandler_{{ sFormIdSanitized }}(); }, 400);
// Remove sticky button when closing modal
$('#{{ sFormId }}').closest('.modal').on('hide.bs.modal', function () {
oStickyRegularButtons_{{ sFormIdSanitized }}.remove();
});
oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_submit').html( oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_submit span.glyphicon')[0].outerHTML );
}
if(oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_cancel span.glyphicon').length > 0)
{
oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_cancel').html( oStickyRegularButtons_{{ sFormIdSanitized }}.find('.form_btn_cancel span.glyphicon')[0].outerHTML );
}
$('#{{ sFormId }}').closest({% if tIsModal == true %}'.modal'{% else %}'#main-content'{% endif %}).append(oStickyRegularButtons_{{ sFormIdSanitized }});
// - Global timeout for any
var oScrollTimeout;
// - Scroll handler
scrollHandler_{{ sFormIdSanitized }} = function () {
if($('#{{ sFormId }} .form_buttons').visible())
{
oStickyRegularButtons_{{ sFormIdSanitized }}.addClass('closed');
}
else
{
oStickyRegularButtons_{{ sFormIdSanitized }}.removeClass('closed');
}
};
// - Event binding for scroll
$({% if tIsModal == true %}'.modal.in'{% else %}window{% endif %}).off('scroll').on('scroll', function () {
if (oScrollTimeout) {
// Clear the timeout, if one is pending
clearTimeout(oScrollTimeout);
oScrollTimeout = null;
}
oScrollTimeout = setTimeout(scrollHandler_{{ sFormIdSanitized }}, 50);
});
// - Event binding for linkedset collapse
$({% if tIsModal == true %}'.modal.in'{% else %}window{% endif %}).off('shown.bs.collapse hidden.bs.collapse').on('shown.bs.collapse hidden.bs.collapse', function () {
scrollHandler_{{ sFormIdSanitized }}();
});
// - Event binding for form building / updating
// Note : We do not want to 'off' the event or it will remove listeners from the widget
oFieldSet_{{ sFormIdSanitized }}.on('form_built', function(oEvent){
scrollHandler_{{ sFormIdSanitized }}();
});
// - Initial test
setTimeout(function(){ scrollHandler_{{ sFormIdSanitized }}(); }, 400);
// Remove sticky button when closing modal
$('#{{ sFormId }}').closest('.modal').on('hide.bs.modal', function () {
oStickyRegularButtons_{{ sFormIdSanitized }}.remove();
});
{% endif %}
{% if tIsModal == true %}

View File

@@ -92,7 +92,7 @@
$(document).ready(function(){
showTableLoader();
// Note : Those options should be externalized in an library so we can use them on any DataTables for the portal.
// We would just have to override / complete the necessary elements
oTable = $('#{{ sTableId }}').DataTable({
@@ -152,8 +152,6 @@
"url": "{{ app.url_generator.generate('p_object_search_from_attribute', {'sTargetAttCode': sTargetAttCode, 'sHostObjectClass': sHostObjectClass, 'sHostObjectId': sHostObjectId, 'ar_token': sActionRulesToken})|raw }}",
"type": "POST",
"data": function(d){
d.sFormPath = '{{ aSource.sFormPath }}';
d.sFieldId = '{{ aSource.sFieldId }}';
d.aObjectIdsToIgnore = {{ aSource.aObjectIdsToIgnore|json_encode()|raw }};
d.iPageNumber = Math.floor(d.start/d.length) + 1;
d.iCountPerPage = d.length;
@@ -170,24 +168,6 @@
// Retrieving values from source form
d.current_values = $('[data-form-path="{{aSource.sFormPath}}"][data-field-id="{{aSource.sFieldId}}"]').closest('.portal_form_handler').portal_form_handler('getCurrentValues');
{% endif %}
},
"error": function(oData, sError, sThrow){
if(oData.responseJSON !== undefined && oData.responseJSON !== null)
{
var oResponse = oData.responseJSON;
// If we encounter an error
if(oResponse.exception !== undefined)
{
// Note : This could be refactored for a global use
$('#{{ sTableId }}').closest('.modal').html( $('#modal-for-alert').html() );
var oModalElem = $('#{{ sTableId }}').closest('.modal');
oModalElem.find('.modal-title').html(oResponse.error_title);
oModalElem.find('.modal-body .alert').html(oResponse.error_message)
.removeClass('alert-success alert-info alert-warning alert-danger')
.addClass('alert-danger');
oModalElem.modal('show');
}
}
}
}
});

View File

@@ -8,7 +8,7 @@
{% if form.buttons is defined and form.buttons.links is defined %}
<div class="form_btn_transitions">
{% for aLink in form.buttons.links %}
<a class="btn btn-primary" href="{{ aLink.url }}">{{ aLink.label }}</a>
<a class="btn btn-default" href="{{ aLink.url }}">{{ aLink.label }}</a>
{% endfor %}
</div>
{% endif %}

View File

@@ -43,7 +43,7 @@
<div class="col-sm-6">
<div class="panel panel-default user_profile_picture">
<div class="panel-heading">
<h3 class="panel-title">{{ 'Brick:Portal:UserProfile:Photo:Title'|dict_s }}</h3>
<h3 class="panel-title">Photo</h3>
</div>
<div class="panel-body" style="position: relative;">
<div class="form_alerts">
@@ -189,11 +189,11 @@
});
// - Undo button
/*$('#user-profile-wrapper .actions .btn_undo').on('click', function(oEvent){
//console.log('Picture undo trigger');
console.log('Picture undo trigger');
});*/
// - Reset button
$('#user-profile-wrapper .actions .btn_reset').on('click', function(oEvent){
//console.log('Picture reset trigger');
console.log('Picture reset trigger');
});
// Submit button

View File

@@ -1,6 +0,0 @@
<div class="content_loader">
<div class="icon glyphicon glyphicon-refresh"></div>
<div class="message">
{{ 'Page:PleaseWait'|dict_s }}
</div>
</div>

View File

@@ -22,99 +22,87 @@
{# This block can be used to add your own meta tags by extending the default template #}
{% block pPageExtraMetas %}
{% endblock %}
<title>{% block pPageTitle %}{% if sPageTitle is defined and sPageTitle is not null %}{{ sPageTitle }} - {{ constant('ITOP_APPLICATION') }}{% else %}{{ 'Page:DefaultTitle'|dict_s }}{% endif %}{% endblock %}</title>
<link rel="shortcut icon" href="{{ app['combodo.absolute_url'] ~ 'images/favicon.ico'|add_itop_version }}" />
<title>{% block pPageTitle %}{% if sPageTitle is defined and sPageTitle is not null %}{{ sPageTitle }} - iTop{% else %}{{ 'Page:DefaultTitle'|dict_s }}{% endif %}{% endblock %}</title>
<link rel="shortcut icon" href="{{ app['combodo.absolute_url'] }}images/favicon.ico?itopversion=$ITOP_VERSION$" />
{% block pPageStylesheets %}
{# First bootstrap core, lib themes, then bootstrap theme, portal adjustements #}
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/bootstrap/css/bootstrap.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] }}lib/bootstrap/css/bootstrap.min.css" rel="stylesheet">
{# - Bootstrap Datetime picker #}
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/bootstrap-datetimepicker/css/bootstrap-datetimepicker.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] }}lib/bootstrap-datetimepicker/css/bootstrap-datetimepicker.min.css" rel="stylesheet">
{# - Datatables #}
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/css/dataTables.bootstrap.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/css/fixedHeader.bootstrap.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/css/responsive.bootstrap.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/css/scroller.bootstrap.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/css/select.bootstrap.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/css/select.dataTables.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] }}lib/datatables/css/dataTables.bootstrap.min.css" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] }}lib/datatables/css/fixedHeader.bootstrap.min.css" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] }}lib/datatables/css/responsive.bootstrap.min.css" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] }}lib/datatables/css/scroller.bootstrap.min.css" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] }}lib/datatables/css/select.bootstrap.min.css" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] }}lib/datatables/css/select.dataTables.min.css" rel="stylesheet">
{# - Font Combodo #}
<link href="{{ app['combodo.absolute_url'] ~ 'css/font-combodo/font-combodo.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.absolute_url'] }}css/font-combodo/font-combodo.css" rel="stylesheet">
{# - Font awesome #}
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/font-awesome/css/font-awesome.min.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] }}lib/font-awesome/css/font-awesome.min.css" rel="stylesheet">
{# - Misc libs #}
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/typeahead/css/typeaheadjs.bootstrap.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.absolute_url'] ~ 'css/magnific-popup.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.portal.base.absolute_url'] }}lib/typeahead/css/typeaheadjs.bootstrap.css" rel="stylesheet">
<link href="{{ app['combodo.absolute_url'] }}css/magnific-popup.css" rel="stylesheet">
{# - Bootstrap theme #}
<link href="{{ app['combodo.portal.instance.conf'].properties.themes.bootstrap|add_itop_version }}" rel="stylesheet" id="css_bootstrap_theme">
<link href="{{ app['combodo.portal.instance.conf'].properties.themes.bootstrap }}" rel="stylesheet" id="css_bootstrap_theme">
{# - Portal adjustments for BS theme #}
<link href="{{ app['combodo.portal.instance.conf'].properties.themes.portal|add_itop_version }}" rel="stylesheet" id="css_portal">
<link href="{{ app['combodo.portal.instance.conf'].properties.themes.portal }}" rel="stylesheet" id="css_portal">
{# Custom CSS that is supposed to do adjustments to the portal #}
{% if app['combodo.portal.instance.conf'].properties.themes.custom is defined %}
<link href="{{ app['combodo.portal.instance.conf'].properties.themes.custom|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.portal.instance.conf'].properties.themes.custom }}" rel="stylesheet">
{% endif %}
{# Others CSS that will come after the theme/portal/custom, in an undefined order #}
{% if app['combodo.portal.instance.conf'].properties.themes.others is defined %}
{% for theme in app['combodo.portal.instance.conf'].properties.themes.others %}
<link href="{{ theme|add_itop_version }}" rel="stylesheet">
<link href="{{ theme }}" rel="stylesheet">
{% endfor %}
{% endif %}
{% endblock %}
{% block pPageScripts %}
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/jquery/jquery-1.11.3.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery-ui-1.10.3.custom.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery.magnific-popup.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery.iframe-transport.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery.fileupload.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/bootstrap/js/bootstrap.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/latinise/latinise.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/jquery/jquery-1.11.3.min.js"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] }}js/jquery-ui-1.10.3.custom.min.js"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] }}js/jquery.magnific-popup.min.js"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] }}js/jquery.fileupload.js"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/latinise/latinise.min.js"></script>
{# Visible.js to check if an element is visible on screen #}
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/jquery-visible/js/jquery.visible.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/jquery-visible/js/jquery.visible.min.js"></script>
{# Base64.js #}
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/jquery-base64/js/jquery.base64.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/jquery-base64/js/jquery.base64.min.js"></script>
{# Moment.js #}
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/moment/js/moment.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/moment/js/moment.min.js"></script>
{# Datatables #}
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/js/jquery.dataTables.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/js/dataTables.bootstrap.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/js/dataTables.fixedHeader.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/js/dataTables.responsive.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/js/dataTables.scroller.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/js/dataTables.select.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/datatables/js/datetime-moment.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'js/dataTables.accentNeutraliseForFilter.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/datatables/js/jquery.dataTables.min.js"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/datatables/js/dataTables.bootstrap.min.js"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/datatables/js/dataTables.fixedHeader.min.js"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/datatables/js/dataTables.responsive.min.js"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/datatables/js/dataTables.scroller.min.js"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/datatables/js/dataTables.select.min.js"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/datatables/js/datetime-moment.js"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}js/dataTables.accentNeutraliseForFilter.js"></script>
{# CKEditor files for HTML WYSIWYG #}
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/ckeditor/ckeditor.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/ckeditor/adapters/jquery.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] }}js/ckeditor/ckeditor.js"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] }}js/ckeditor/adapters/jquery.js"></script>
{# Date-time picker for Bootstrap #}
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/bootstrap-datetimepicker/js/bootstrap-datetimepicker.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/bootstrap-datetimepicker/js/bootstrap-datetimepicker.min.js"></script>
{# Typeahead files for autocomplete #}
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/typeahead/js/bloodhound.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/typeahead/js/typeahead.bundle.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/typeahead/js/typeahead.jquery.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/handlebars/js/handlebars.min-768ddbd.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/typeahead/js/bloodhound.min.js"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/typeahead/js/typeahead.bundle.min.js"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/typeahead/js/typeahead.jquery.min.js"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}lib/handlebars/js/handlebars.min-768ddbd.js"></script>
{# Form files #}
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/form_handler.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/form_field.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/subform_field.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/field_set.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] }}js/form_handler.js"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] }}js/form_field.js"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] }}js/subform_field.js"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] }}js/field_set.js"></script>
{# Form files for portal #}
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'js/portal_form_handler.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'js/portal_form_field.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'js/portal_form_field_html.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}js/portal_form_handler.js"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}js/portal_form_field.js"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] }}js/portal_form_field_html.js"></script>
{% endblock %}
</head>
<body class="{% block pPageBodyClass %}{% endblock %}">
{% block pPageBodyWrapper %}
{% block pEnvBannerWrapper %}
{% if app['combodo.current_environment'] != 'production' %}
<div id="envbanner" class="alert alert-danger" role="alert">
{{ 'Portal:EnvironmentBanner:Title'|dict_format( app['combodo.current_environment']|upper )|raw }}
<button type="button" onclick="window;location.href='{{ app['url_generator'].generate('p_home', {'switch_env': 'production'}) }}'">
{{ 'Portal:EnvironmentBanner:GoToProduction'|dict_s|raw }}
</button>
</div>
{% endif %}
{% endblock %}
{% block pNavigationWrapper %}
{# Topbar navigation menu for mobile screens #}
<nav class="navbar navbar-fixed-top navbar-default visible-xs" id="topbar" role="navigation">
@@ -272,7 +260,12 @@
<div class="modal fade" id="modal-for-all" role="dialog">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
{% include 'itop-portal-base/portal/src/views/helpers/loader.html.twig' %}
<div class="content_loader">
<div class="icon glyphicon glyphicon-refresh"></div>
<div class="message">
{{ 'Page:PleaseWait'|dict_s }}
</div>
</div>
</div>
</div>
</div>
@@ -296,7 +289,12 @@
<div id="page_overlay" class="global_overlay">
<div class="overlay_content">
{% include 'itop-portal-base/portal/src/views/helpers/loader.html.twig' %}
<div class="content_loader">
<div class="icon glyphicon glyphicon-refresh"></div>
<div class="message">
{{ 'Page:PleaseWait'|dict_s }}
</div>
</div>
</div>
</div>
{% endblock %}
@@ -307,22 +305,19 @@
{
return '{{ app['combodo.absolute_url'] }}';
};
var AddParameterToUrl = function(sUrl, sParamName, sParamValue)
var addParameterToUrl = function(sUrl, sParamName, sParamValue)
{
sUrl += (sUrl.split('?')[1] ? '&':'?') + sParamName + '=' + sParamValue;
return sUrl;
};
var GetContentLoaderTemplate = function()
{
return '<div class="content_loader"><div class="icon glyphicon glyphicon-refresh"></div><div class="message">{{ 'Page:PleaseWait'|dict_s }}</div></div>';
}
var contentLoaderTemplate = '<div class="content_loader"><div class="icon glyphicon glyphicon-refresh"></div><div class="message">{{ 'Page:PleaseWait'|dict_s }}</div></div>';
$(document).ready(function(){
{% block pPageReadyScripts %}
// Hack to enable a same modal to load content from different urls
$('body').on('hidden.bs.modal', '.modal#modal-for-all', function () {
$(this).removeData('bs.modal');
$(this).find('.modal-content').html(GetContentLoaderTemplate());
$(this).find('.modal-content').html(contentLoaderTemplate);
});
// Hack to enable multiple modals by making sure the .modal-open class is set to the <body> when there is at least one modal open left
$('body').on('hidden.bs.modal', function () {
@@ -340,7 +335,7 @@
$('body').on('loaded.bs.modal', function (oEvent) {
var sModalContent = $(oEvent.target).find('.modal-content').html();
if( (sModalContent === '') || (sModalContent.replace(/[\n\r\t]+/g, '') === GetContentLoaderTemplate()) )
if( (sModalContent === '') || (sModalContent.replace(/[\n\r\t]+/g, '') === contentLoaderTemplate) )
{
$(oEvent.target).find('.modal-content').html($('#modal-for-alert .modal-content').html());
$(oEvent.target).find('.modal-content .modal-header .modal-title').text('{{ 'Error:HTTP:500'|dict_s }}');

View File

@@ -1,14 +1,12 @@
{# modal/layout.html.twig #}
{# Base modal layout, used to fill Bootstrap .modal-content #}
{% block pModalContent %}
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">{% block pModalTitle %}{% endblock %}</h4>
</div>
<div class="modal-body">{% block pModalBody %}{% endblock %}</div>
<div class="modal-footer">
{% block pModalFooter %}
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'Portal:ButtonClose'|dict_s }}</button>
{% endblock %}
</div>
{% endblock %}
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">{% block pModalTitle %}{% endblock %}</h4>
</div>
<div class="modal-body">{% block pModalBody %}{% endblock %}</div>
<div class="modal-footer">
{% block pModalFooter %}
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'Portal:ButtonClose'|dict_s }}</button>
{% endblock %}
</div>

View File

@@ -1,15 +0,0 @@
{# itop-portal-base/portal/src/views/bricks/object/mode_loader.html.twig #}
{# Modal loader layout #}
{% extends 'itop-portal-base/portal/src/views/modal/layout.html.twig' %}
{% block pModalContent %}
{% include 'itop-portal-base/portal/src/views/helpers/loader.html.twig' %}
{% if redirection is defined and redirection.url is defined %}
<script type="text/javascript">
$(document).ready( function(){
window.location = '{{ redirection.url|raw }}';
});
</script>
{% endif %}
{% endblock %}

View File

@@ -15,17 +15,6 @@
footer {
margin: 5em 1em;
}
/* Environment banner */
#envbanner {
position: relative;
z-index: 10;
padding: 5px 15px;
text-align: center;
}
#envbanner > button {
margin-left: 5px;
color: #000;
}
/* Navigation menu */
.navbar-nav .dropdown-menu a .glyphicon, .user_infos .dropdown-menu a .glyphicon {
margin-right: 15px;
@@ -278,10 +267,6 @@ footer {
.mfp-wrap {
z-index: 1210;
}
.mfp-img {
cursor: pointer;
cursor: zoom-out;
}
/********************/
/* Typeahed setting */
/********************/
@@ -453,10 +438,6 @@ footer {
.dataTables_wrapper {
padding: 10px 10px;
}
.dataTable.table td img {
max-width: 100%;
height: initial !important;
}
#brick_content_toolbar {
/* margin: 10px 0px 6px 0px; */
padding: 10px;
@@ -621,11 +602,6 @@ table .group-actions {
color: #ea7d1e;
font-size: 0.9em;
}
/* InlineImage */
.inline-image {
cursor: pointer;
cursor: zoom-in;
}
/* CaseLog field */
.caselog_field_entry {
border: 1px solid #ddd;
@@ -646,7 +622,6 @@ table .group-actions {
font-size: 16px;
border: 1px solid #a6a6a6;
border-bottom-color: #979797;
cursor: pointer;
}
.caselog_field_entry_button:hover {
background-color: #ccc;
@@ -663,12 +638,10 @@ table .group-actions {
}
/* LinkedSet*/
.form_linkedset_toggler, .form_linkedset_toggler:hover, .form_linkedset_toggler:focus {
margin-left: 0.4em;
text-decoration: none;
color: inherit;
}
.form_linkedset_toggler > .text {
margin-left: 0.4em;
}
.form_linkedset_toggler > .text:before {
content: "(";
}
@@ -823,10 +796,6 @@ table .group-actions {
}
}
}
/* BlobField */
.form_fields .file_open_link {
margin-left: 10px;
}
.form_field .form-control-static img {
max-width: 100% !important;
height: initial !important;
@@ -847,8 +816,7 @@ table .group-actions {
@media (min-width: 768px) {
/* Making regular button sticky */
.form_buttons .form_btn_transitions {
float: right !important;
margin-left: 3px;
float: left !important;
}
.form_buttons .form_btn_regular {
text-align: right;
@@ -917,17 +885,9 @@ table .group-actions {
border-color: #fbeed5;
color: #c09853;
}
/* CKEditor : Misc */
.cke_toolbox_collapser, .cke_toolbox_collapser .cke_arrow {
cursor: pointer !important;
}
/* DataTables : Selection inputs */
.dataTable.table th span.row_input, .dataTable.table td span.row_input {
display: inline-block;
width: 100%;
text-align: center;
}
/* Wiki text (hyperlinks) */
.wiki_broken_link {
text-decoration: line-through;
}

View File

@@ -19,18 +19,6 @@ footer{
margin: 5em 1em;
}
/* Environment banner */
#envbanner{
position: relative;
z-index: 10;
padding: 5px 15px;
text-align: center;
}
#envbanner > button{
margin-left: 5px;
color: #000;
}
/* Navigation menu */
.navbar-nav .dropdown-menu a .glyphicon,
.user_infos .dropdown-menu a .glyphicon{
@@ -294,10 +282,6 @@ footer{
.mfp-wrap{
z-index: 1210;
}
.mfp-img{
cursor: pointer;
cursor: zoom-out;
}
/********************/
/* Typeahed setting */
@@ -477,10 +461,6 @@ footer{
.dataTables_wrapper{
padding: 10px 10px;
}
.dataTable.table td img{
max-width: 100%;
height: initial !important;
}
#brick_content_toolbar{
/* margin: 10px 0px 6px 0px; */
padding: 10px;
@@ -660,11 +640,6 @@ table .group-actions .item-action-wrapper .panel-body > p:last-child{
color: $brand-primary;
font-size: 0.9em;
}
/* InlineImage */
.inline-image{
cursor: pointer;
cursor: zoom-in;
}
/* CaseLog field */
.caselog_field_entry{
border: 1px solid $gray-lighter;
@@ -685,7 +660,6 @@ table .group-actions .item-action-wrapper .panel-body > p:last-child{
font-size: 16px;
border: 1px solid #a6a6a6;
border-bottom-color: #979797;
cursor: pointer;
}
.caselog_field_entry_button:hover{
background-color: #cccccc;
@@ -704,12 +678,10 @@ table .group-actions .item-action-wrapper .panel-body > p:last-child{
.form_linkedset_toggler,
.form_linkedset_toggler:hover,
.form_linkedset_toggler:focus{
margin-left: 0.4em;
text-decoration: none;
color: inherit;
}
.form_linkedset_toggler > .text{
margin-left: 0.4em;
}
.form_linkedset_toggler > .text:before{
content: "(";
}
@@ -864,10 +836,6 @@ table .group-actions .item-action-wrapper .panel-body > p:last-child{
}
}
}
/* BlobField */
.form_fields .file_open_link{
margin-left: 10px;
}
.form_field .form-control-static img{
max-width: 100% !important;
@@ -889,8 +857,7 @@ table .group-actions .item-action-wrapper .panel-body > p:last-child{
}
@media (min-width: 768px){
.form_buttons .form_btn_transitions{
float: right !important;
margin-left: 3px;
float: left !important;
}
.form_buttons .form_btn_regular{
text-align: right;
@@ -960,11 +927,6 @@ table .group-actions .item-action-wrapper .panel-body > p:last-child{
border-color: $alert-warning-border;
color: $alert-warning-text;
}
/* CKEditor : Misc */
.cke_toolbox_collapser,
.cke_toolbox_collapser .cke_arrow{
cursor: pointer !important;
}
/* DataTables : Selection inputs */
.dataTable.table th span.row_input,
@@ -972,8 +934,4 @@ table .group-actions .item-action-wrapper .panel-body > p:last-child{
display: inline-block;
width: 100%;
text-align: center;
}
/* Wiki text (hyperlinks) */
.wiki_broken_link {
text-decoration: line-through;
}

View File

@@ -73,16 +73,12 @@ $oApp->register(new Combodo\iTop\Portal\Provider\ScopeValidatorServiceProvider()
'scope_validator.instance_name' => PORTAL_ID
));
$oApp->register(new Silex\Provider\TwigServiceProvider(), array(
'twig.path' => MODULESROOT,
'twig.options' => array(
'cache' => utils::GetCachePath() . 'twig/'
)
'twig.path' => MODULESROOT
));
$oApp->register(new Silex\Provider\HttpFragmentServiceProvider());
// Configuring Silex application
$oApp['debug'] = $bDebug;
$oApp['combodo.current_environment'] = utils::GetCurrentEnvironment();
$oApp['combodo.absolute_url'] = utils::GetAbsoluteUrlAppRoot();
$oApp['combodo.portal.base.absolute_url'] = utils::GetAbsoluteUrlAppRoot() . 'env-' . utils::GetCurrentEnvironment() . '/itop-portal-base/portal/web/';
$oApp['combodo.portal.base.absolute_path'] = MODULESROOT . '/itop-portal-base/portal/web/';

View File

@@ -135,16 +135,6 @@ $(function()
// If everything is okay, we close the form and reload it.
if(oValidation.valid)
{
// Resetting textarea fields (delay is necessary has we have to wait for the form to be built.
setTimeout(function(){
me.options.field_set.find('.portal_form_field_html').each(function(iIndex, oElem){
if($(oElem).find('.cke').length > 0)
{
$(oElem).triggerHandler('set_current_value', '');
}
});
}, 200);
if(me.options.is_modal)
{
me.element.closest('.modal').modal('hide');
@@ -181,13 +171,7 @@ $(function()
oModalElem.attr('id', '').appendTo('body');
// Loading content
oModalElem.find('.modal-content').html($('#page_overlay .overlay_content').html());
oModalElem.find('.modal-content').load(sUrl, {
// Passing formmanager data to the next page, just in case it needs it (eg. when applying stimulus)
formmanager_class: me.options.formmanager_class,
formmanager_data: JSON.stringify(me.options.formmanager_data)
}
);
oModalElem.find('.modal-content').load(sUrl);
oModalElem.modal('show');
}
else

View File

@@ -1,99 +0,0 @@
<?php
/**
* Локализация интерфейса Combodo iTop подготовлена сообществом iTop по-русски http://community.itop-itsm.ru.
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @link http://community.itop-itsm.ru iTop Russian Community
* @link https://github.com/itop-itsm-ru/itop-rus
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*
*/
// Portal
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Page:DefaultTitle' => 'Пользовательский портал iTop',
'Page:PleaseWait' => 'Пожалуйста, подождите...',
'Page:Home' => 'Домашняя страница',
'Page:GoPortalHome' => 'Домашняя страница',
'Page:GoPreviousPage' => 'Предыдущяя страница',
'Portal:Button:Submit' => 'Применить',
'Portal:Button:Cancel' => 'Отменить',
'Portal:Button:Close' => 'Закрыть',
'Portal:Button:Add' => 'Добавить',
'Portal:Button:Remove' => 'Удалить',
'Portal:Button:Delete' => 'Удалить',
'Error:HTTP:404' => 'Страница не найдена',
'Error:HTTP:500' => 'Упс! Произошла ошибка.',
'Error:XHR:Fail' => 'Не удалось загрузить данные. Пожалуйста, свяжитесь с вашим администратором iTop.',
'Error:HTTP:GetHelp' => 'Пожалуйста, свяжитесь с вашим администратором iTop, если проблема сохраняется.',
'Portal:Datatables:Language:Processing' => 'Пожалуйста, подождите...',
'Portal:Datatables:Language:Search' => 'Фильтр :',
'Portal:Datatables:Language:LengthMenu' => 'Показывать _MENU_ элементов на странице',
'Portal:Datatables:Language:ZeroRecords' => 'Нет записей',
'Portal:Datatables:Language:Info' => 'Страница _PAGE_ из _PAGES_',
'Portal:Datatables:Language:InfoEmpty' => 'Нет информации',
'Portal:Datatables:Language:InfoFiltered' => 'Отфильтровано из _MAX_ элементов',
'Portal:Datatables:Language:EmptyTable' => 'Нет данных в этой таблице',
'Portal:Datatables:Language:DisplayLength:All' => 'Все',
'Portal:Datatables:Language:Paginate:First' => 'Первая',
'Portal:Datatables:Language:Paginate:Previous' => 'Предыдущая',
'Portal:Datatables:Language:Paginate:Next' => 'Следующая',
'Portal:Datatables:Language:Paginate:Last' => 'Последняя',
'Portal:Datatables:Language:Sort:Ascending' => 'Включить сортировку по возрастанию',
'Portal:Datatables:Language:Sort:Descending' => 'Включить сортировку по убыванию',
'Portal:Autocomplete:NoResult' => 'Нет данных',
'Portal:Attachments:DropZone:Message' => 'Перетащите файл для добавления вложения',
));
// UserProfile brick
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Brick:Portal:UserProfile:Name' => 'Профиль пользователя',
'Brick:Portal:UserProfile:Navigation:Dropdown:MyProfil' => 'Мой профиль',
'Brick:Portal:UserProfile:Navigation:Dropdown:Logout' => 'Выйти',
'Brick:Portal:UserProfile:Password:Title' => 'Пароль',
'Brick:Portal:UserProfile:Password:ChoosePassword' => 'Введите новый пароль',
'Brick:Portal:UserProfile:Password:ConfirmPassword' => 'Подтвердите новый пароль',
'Brick:Portal:UserProfile:Password:CantChangeContactAdministrator' => 'Пожалуйста, свяжитесь с вашим администратором iTop для изменения пароля.',
'Brick:Portal:UserProfile:Password:CantChangeForUnknownReason' => 'Не удалось изменить пароль, пожалуйста, свяжитесь с вашим администратором iTop.',
'Brick:Portal:UserProfile:PersonalInformations:Title' => 'Персональная информация',
'Brick:Portal:UserProfile:Photo:Title' => 'Фотография',
));
// BrowseBrick brick
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Brick:Portal:Browse:Name' => 'Просмотр элементов',
'Brick:Portal:Browse:Mode:List' => 'Список',
'Brick:Portal:Browse:Mode:Tree' => 'Дерево',
'Brick:Portal:Browse:Action:Drilldown' => 'Детализация',
'Brick:Portal:Browse:Action:View' => 'Подробно',
'Brick:Portal:Browse:Action:Edit' => 'Изменить',
'Brick:Portal:Browse:Action:Create' => 'Создать',
'Brick:Portal:Browse:Action:CreateObjectFromThis' => 'Новый %1$s',
'Brick:Portal:Browse:Tree:ExpandAll' => 'Развернуть все',
'Brick:Portal:Browse:Tree:CollapseAll' => 'Свернуть все',
'Brick:Portal:Browse:Filter:NoData' => 'Нет элементов',
));
// ManageBrick brick
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Brick:Portal:Manage:Name' => 'Управление элементами',
'Brick:Portal:Manage:Table:NoData' => 'Нет элементов',
));
// ObjectBrick brick
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Brick:Portal:Object:Name' => 'Object',
'Brick:Portal:Object:Form:Create:Title' => 'Создать %1$s',
'Brick:Portal:Object:Form:Edit:Title' => 'Обновление %2$s (%1$s)',
'Brick:Portal:Object:Form:View:Title' => '%1$s : %2$s',
'Brick:Portal:Object:Form:Stimulus:Title' => 'Пожалуйста, укажите следующую информацию:',
'Brick:Portal:Object:Form:Message:Saved' => 'Сохранено',
'Brick:Portal:Object:Search:Regular:Title' => 'Выбрать %1$s (%2$s)',
'Brick:Portal:Object:Search:Hierarchy:Title' => 'Выбрать %1$s (%2$s)',
));
// CreateBrick brick
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Brick:Portal:Create:Name' => 'Быстрое создание',
));

View File

@@ -37,5 +37,4 @@ $sDir = basename(__DIR__);
define('PORTAL_MODULE_ID', $sDir);
define('PORTAL_ID', $sDir);
ApplicationContext::SetUrlMakerClass('iTopPortalViewUrlMaker');
require_once APPROOT . '/env-' . utils::GetCurrentEnvironment() . '/itop-portal-base/portal/web/index.php';

View File

@@ -22,26 +22,20 @@
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class iTopPortalEditUrlMaker implements iDBObjectURLMaker
class iTopPortalUrlMaker implements iDBObjectURLMaker
{
/**
* Generate an (absolute) URL to an object, either in view or edit mode
* @param string $sClass The class of the object
* @param int $iId The identifier of the object
* @param string $sMode edit|view
* @return string
*/
public static function PrepareObjectURL($sClass, $iId, $sMode)
public static function MakeObjectURL($sClass, $iId)
{
require_once APPROOT . '/lib/silex/vendor/autoload.php';
require_once APPROOT . '/env-' . utils::GetCurrentEnvironment() . '/itop-portal-base/portal/src/providers/urlgeneratorserviceprovider.class.inc.php';
require_once APPROOT . '/env-' . utils::GetCurrentEnvironment() . '/itop-portal-base/portal/src/helpers/urlgeneratorhelper.class.inc.php';
require_once APPROOT . '/env-' . utils::GetCurrentEnvironment() . '/itop-portal-base/portal/src/helpers/applicationhelper.class.inc.php';
// Using a static var allows to preserve the object through function calls
static $oApp = null;
static $sPortalId = null;
// Initializing Silex app
if ($oApp === null)
{
@@ -55,51 +49,15 @@ class iTopPortalEditUrlMaker implements iDBObjectURLMaker
// Retrieving portal id
$sPortalId = basename(__DIR__);
}
// The object is reachable in the specified mode (edit/view)
switch($sMode)
{
case 'view':
$sObjectQueryString = $oApp['url_generator']->generate('p_object_view', array('sObjectClass' => $sClass, 'sObjectId' => $iId));
break;
case 'edit':
default:
$sObjectQueryString = $oApp['url_generator']->generate('p_object_edit', array('sObjectClass' => $sClass, 'sObjectId' => $iId));
}
$sObjectQueryString = $oApp['url_generator']->generate('p_object_edit', array('sObjectClass' => $sClass, 'sObjectId' => $iId));
$sPortalAbsoluteUrl = utils::GetAbsoluteUrlModulePage($sPortalId, 'index.php');
if (strpos($sPortalAbsoluteUrl, '?') !== false)
{
$sUrl = substr($sPortalAbsoluteUrl, 0, strpos($sPortalAbsoluteUrl, '?')).$sObjectQueryString;
}
else
{
$sUrl = $sPortalAbsoluteUrl.$sObjectQueryString;
}
$sUrl = str_replace('?', $sObjectQueryString . '?', $sPortalAbsoluteUrl);
return $sUrl;
}
public static function MakeObjectURL($sClass, $iId)
{
return static::PrepareObjectURL($sClass, $iId, 'edit');
}
}
/**
* Hyperlinks to the "view" of the object (vs edition)
* @author denis
*
*/
class iTopPortalViewUrlMaker extends iTopPortalEditUrlMaker
{
public static function MakeObjectURL($sClass, $iId)
{
return static::PrepareObjectURL($sClass, $iId, 'view');
}
}
// Default portal hyperlink (for notifications) is the edit hyperlink
DBObject::RegisterURLMakerClass('portal', 'iTopPortalEditUrlMaker');
DBObject::RegisterURLMakerClass('portal', 'iTopPortalUrlMaker');

View File

@@ -2,30 +2,67 @@
/**
* Локализация интерфейса Combodo iTop подготовлена сообществом iTop по-русски http://community.itop-itsm.ru.
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @license http://opensource.org/licenses/AGPL-3.0
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @link http://community.itop-itsm.ru iTop Russian Community
* @link https://github.com/itop-itsm-ru/itop-rus
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*
* Инструкция по установке
*
* Процесс установки заключается в замене имеющихся локализационных файлов полученными и последующем запуске процедуры обновления iTop для перекомпиляции кода.
* 1. Скопируйте с заменой два полученных файла из "itop-rus/dictionaries" в "путь/до/вашего/itop/dictionaries".
* 2. Скопируйте с заменой полученные файлы "itop-rus/datamodels/2.x/название-модуля/ru.dict.название-модуля.php" в "путь/до/вашего/itop/datamodels/2.x/название-модуля".
* 3. Перейдите по адресу "http://адрес/вашего/itop/setup", при этом файл "путь/до/вашего/itop/conf/production/config-itop.php" должен быть доступен для записи.
* 4. На второй странице установщика выберите "Upgrade an existing iTop instance" и следуйте дальнейшим инструкциям установщика.
*
* Ответы на вопросы по установке и использованию переводов, а также на любые другие вопросы по iTop всегда можно получить на сайте сообщества iTop по-русски http://community.itop-itsm.ru.
*
*/
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//////////////////////////////////////////////////////////////////////
// Classes in 'bizmodel'
//////////////////////////////////////////////////////////////////////
//
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Menu:ProblemManagement' => 'Управление проблемами',
'Menu:ProblemManagement+' => 'Управление проблемами',
'Menu:Problem:Overview' => 'Обзор',
'Menu:Problem:Overview+' => 'Управление проблемами - Обзор',
'Menu:NewProblem' => 'Новая проблема',
'Menu:NewProblem+' => 'Создать новую проблему',
'Menu:SearchProblems' => 'Поиск проблем',
'Menu:SearchProblems+' => 'Поиск проблем',
'Menu:Problem:Shortcuts' => 'Ярлыки',
'Menu:Problem:MyProblems' => 'Назначенные мне',
'Menu:Problem:MyProblems+' => 'Назначенные мне проблемы',
'Menu:Problem:OpenProblems' => 'Открытые',
'Menu:Problem:OpenProblems+' => 'Все открытые проблемы',
'UI-ProblemManagementOverview-ProblemByService' => 'Проблемы по услугам',
'UI-ProblemManagementOverview-ProblemByService+' => 'Проблемы по услугам',
'Menu:ProblemManagement' => 'Управление проблемами',
'Menu:ProblemManagement+' => 'Управление проблемами',
'Menu:Problem:Overview' => 'Обзор',
'Menu:Problem:Overview+' => 'Overview',
'Menu:NewProblem' => 'Создать проблему',
'Menu:NewProblem+' => 'Новая проблема',
'Menu:SearchProblems' => 'Найти проблему',
'Menu:SearchProblems+' => 'Search for problems',
'Menu:Problem:Shortcuts' => 'Ярлыки',
'Menu:Problem:MyProblems' => 'Назначенные мне проблемы',
'Menu:Problem:MyProblems+' => 'Мои проблемы',
'Menu:Problem:OpenProblems' => 'Открытые проблемы',
'Menu:Problem:OpenProblems+' => 'Все открытые проблемы',
'UI-ProblemManagementOverview-ProblemByService' => 'Проблемы по сервису',
'UI-ProblemManagementOverview-ProblemByService+' => 'Проблемы по сервису',
'UI-ProblemManagementOverview-ProblemByPriority' => 'Проблемы по приоритету',
'UI-ProblemManagementOverview-ProblemByPriority+' => 'Проблемы по приоритету',
'UI-ProblemManagementOverview-ProblemUnassigned' => 'Неназначенные проблемы',
@@ -53,56 +90,54 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Problem/Attribute:status/Value:closed+' => '',
'Class:Problem/Attribute:service_id' => 'Услуга',
'Class:Problem/Attribute:service_id+' => '',
'Class:Problem/Attribute:service_name' => 'Услуга',
'Class:Problem/Attribute:service_name' => 'Имя услуги',
'Class:Problem/Attribute:service_name+' => '',
'Class:Problem/Attribute:servicesubcategory_id' => 'Подкатегория',
'Class:Problem/Attribute:servicesubcategory_id+' => 'Подкатегория услуги',
'Class:Problem/Attribute:servicesubcategory_name' => 'Подкатегория услуги',
'Class:Problem/Attribute:servicesubcategory_id' => 'Тип запроса',
'Class:Problem/Attribute:servicesubcategory_id+' => '',
'Class:Problem/Attribute:servicesubcategory_name' => 'Тип запроса',
'Class:Problem/Attribute:servicesubcategory_name+' => '',
'Class:Problem/Attribute:product' => 'Продукт',
'Class:Problem/Attribute:product+' => '',
'Class:Problem/Attribute:impact' => 'Влияние',
'Class:Problem/Attribute:impact+' => '',
'Class:Problem/Attribute:impact/Value:1' => 'Департамент',
'Class:Problem/Attribute:impact/Value:1' => 'Услуга',
'Class:Problem/Attribute:impact/Value:1+' => '',
'Class:Problem/Attribute:impact/Value:2' => 'Служба',
'Class:Problem/Attribute:impact/Value:2' => 'Отдел',
'Class:Problem/Attribute:impact/Value:2+' => '',
'Class:Problem/Attribute:impact/Value:3' => 'Персона',
'Class:Problem/Attribute:impact/Value:3+' => '',
'Class:Problem/Attribute:urgency' => 'Срочность',
'Class:Problem/Attribute:urgency+' => '',
'Class:Problem/Attribute:urgency/Value:1' => 'Критическая',
'Class:Problem/Attribute:urgency/Value:1+' => 'Критическая',
'Class:Problem/Attribute:urgency/Value:1+' => 'critical',
'Class:Problem/Attribute:urgency/Value:2' => 'Высокая',
'Class:Problem/Attribute:urgency/Value:2+' => 'Высокая',
'Class:Problem/Attribute:urgency/Value:2+' => 'high',
'Class:Problem/Attribute:urgency/Value:3' => 'Средняя',
'Class:Problem/Attribute:urgency/Value:3+' => 'Средняя',
'Class:Problem/Attribute:urgency/Value:3+' => 'medium',
'Class:Problem/Attribute:urgency/Value:4' => 'Низкая',
'Class:Problem/Attribute:urgency/Value:4+' => 'Низкая',
'Class:Problem/Attribute:urgency/Value:4+' => 'low',
'Class:Problem/Attribute:priority' => 'Приоритет',
'Class:Problem/Attribute:priority+' => '',
'Class:Problem/Attribute:priority/Value:1' => 'Критический',
'Class:Problem/Attribute:priority/Value:1+' => 'Критический',
'Class:Problem/Attribute:priority/Value:1+' => 'Critical',
'Class:Problem/Attribute:priority/Value:2' => 'Высокий',
'Class:Problem/Attribute:priority/Value:2+' => 'Высокий',
'Class:Problem/Attribute:priority/Value:2+' => 'High',
'Class:Problem/Attribute:priority/Value:3' => 'Средний',
'Class:Problem/Attribute:priority/Value:3+' => 'Средний',
'Class:Problem/Attribute:priority/Value:3+' => 'Medium',
'Class:Problem/Attribute:priority/Value:4' => 'Низкий',
'Class:Problem/Attribute:priority/Value:4+' => 'Низкий',
'Class:Problem/Attribute:priority/Value:4+' => 'Low',
'Class:Problem/Attribute:related_change_id' => 'Связанное изменение',
'Class:Problem/Attribute:related_change_id+' => '',
'Class:Problem/Attribute:related_change_ref' => 'Связанное изменение',
'Class:Problem/Attribute:related_change_ref' => 'Ссылка на изменение',
'Class:Problem/Attribute:related_change_ref+' => '',
'Class:Problem/Attribute:assignment_date' => 'Дата назначения',
'Class:Problem/Attribute:assignment_date' => 'Назначение',
'Class:Problem/Attribute:assignment_date+' => '',
'Class:Problem/Attribute:resolution_date' => 'Дата решения',
'Class:Problem/Attribute:resolution_date' => 'Решение',
'Class:Problem/Attribute:resolution_date+' => '',
'Class:Problem/Attribute:knownerrors_list' => 'Известные ошибки',
'Class:Problem/Attribute:knownerrors_list+' => 'Связанные известные ошибки',
'Class:Problem/Attribute:related_request_list' => 'Запросы',
'Class:Problem/Attribute:related_request_list+' => 'Связанные запросы',
'Class:Problem/Attribute:related_incident_list' => 'Инциденты',
'Class:Problem/Attribute:related_incident_list+' => 'Связанные инциденты',
'Class:Problem/Stimulus:ev_assign' => 'Назначить',
'Class:Problem/Stimulus:ev_assign+' => '',
'Class:Problem/Stimulus:ev_reassign' => 'Переназначить',
@@ -111,4 +146,8 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Problem/Stimulus:ev_resolve+' => '',
'Class:Problem/Stimulus:ev_close' => 'Закрыть',
'Class:Problem/Stimulus:ev_close+' => '',
));
'Class:Problem/Attribute:related_incident_list' => 'Related incidents~~',
'Class:Problem/Attribute:related_incident_list+' => 'All the incidents that are related to this problem~~',
));
?>

View File

@@ -1325,7 +1325,7 @@
<code><![CDATA[ public function UpdateChildRequestLog()
{
$oLog = $this->Get('public_log');
$sLogPublic = $oLog->GetModifiedEntry('html');
$sLogPublic = $oLog->GetModifiedEntry();
if ($sLogPublic != '')
{
$sOQL = "SELECT UserRequest WHERE parent_request_id=:ticket";
@@ -1343,7 +1343,7 @@
}
$oLog = $this->Get('private_log');
$sLogPrivate = $oLog->GetModifiedEntry('html');
$sLogPrivate = $oLog->GetModifiedEntry();
if ($sLogPrivate != '')
{
$sOQL = "SELECT UserRequest WHERE parent_request_id=:ticket";

View File

@@ -1,255 +0,0 @@
<?php
/**
* Локализация интерфейса Combodo iTop подготовлена сообществом iTop по-русски http://community.itop-itsm.ru.
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @link http://community.itop-itsm.ru iTop Russian Community
* @link https://github.com/itop-itsm-ru/itop-rus
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*
*/
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Menu:RequestManagement' => 'Управление запросами',
'Menu:RequestManagement+' => 'Управление запросами',
'Menu:RequestManagementProvider' => 'Поставщик техподдержки',
'Menu:RequestManagementProvider+' => 'Поставщик техподдержки',
'Menu:UserRequest:Provider' => 'Открытые запросы, отправленные поставщику',
'Menu:UserRequest:Provider+' => 'Открытые запросы, отправленные поставщику',
'Menu:UserRequest:Overview' => 'Обзор',
'Menu:UserRequest:Overview+' => 'Обзор',
'Menu:NewUserRequest' => 'Новый запрос',
'Menu:NewUserRequest+' => 'Создать новый запрос на обслуживание',
'Menu:SearchUserRequests' => 'Поиск запросов',
'Menu:SearchUserRequests+' => 'Поиск запросов на обслуживание',
'Menu:UserRequest:Shortcuts' => 'Ярлыки',
'Menu:UserRequest:Shortcuts+' => 'Ярлыки',
'Menu:UserRequest:MyRequests' => 'Назначенные мне',
'Menu:UserRequest:MyRequests+' => 'Назначенные мне запросы',
'Menu:UserRequest:MySupportRequests' => "Созданные мной",
'Menu:UserRequest:MySupportRequests+' => "Созданные мной запросы",
'Menu:UserRequest:EscalatedRequests' => 'Эскалированные',
'Menu:UserRequest:EscalatedRequests+' => 'Эскалированные запросы',
'Menu:UserRequest:OpenRequests' => 'Открытые',
'Menu:UserRequest:OpenRequests+' => 'Открытые запросы',
'UI:WelcomeMenu:MyAssignedCalls' => 'Назначенные мне запросы',
'UI-RequestManagementOverview-RequestByType-last-14-days' => 'Запросы по типу за 14 дней',
'UI-RequestManagementOverview-Last-14-days' => 'Количество запросов за 14 дней',
'UI-RequestManagementOverview-OpenRequestByStatus' => 'Открытые запросы по статусу',
'UI-RequestManagementOverview-OpenRequestByAgent' => 'Открытые запросы по агенту',
'UI-RequestManagementOverview-OpenRequestByType' => 'Открытые запросы по типу',
'UI-RequestManagementOverview-OpenRequestByCustomer' => 'Открытые запросы по заказчику',
'Class:UserRequest:KnownErrorList' => 'Известные ошибки',
));
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: UserRequest
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:UserRequest' => 'Запрос',
'Class:UserRequest+' => '',
'Class:UserRequest/Attribute:status' => 'Статус',
'Class:UserRequest/Attribute:status+' => '',
'Class:UserRequest/Attribute:status/Value:new' => 'Новый',
'Class:UserRequest/Attribute:status/Value:new+' => '',
'Class:UserRequest/Attribute:status/Value:escalated_tto' => 'Эскалация TTO',
'Class:UserRequest/Attribute:status/Value:escalated_tto+' => '',
'Class:UserRequest/Attribute:status/Value:assigned' => 'Назначен',
'Class:UserRequest/Attribute:status/Value:assigned+' => '',
'Class:UserRequest/Attribute:status/Value:escalated_ttr' => 'Эскалация TTR',
'Class:UserRequest/Attribute:status/Value:escalated_ttr+' => '',
'Class:UserRequest/Attribute:status/Value:waiting_for_approval' => 'Ожидание утверждения',
'Class:UserRequest/Attribute:status/Value:waiting_for_approval+' => '',
'Class:UserRequest/Attribute:status/Value:approved' => 'Утвержден',
'Class:UserRequest/Attribute:status/Value:approved+' => '',
'Class:UserRequest/Attribute:status/Value:rejected' => 'Отклонен',
'Class:UserRequest/Attribute:status/Value:rejected+' => '',
'Class:UserRequest/Attribute:status/Value:pending' => 'В ожидании',
'Class:UserRequest/Attribute:status/Value:pending+' => '',
'Class:UserRequest/Attribute:status/Value:resolved' => 'Решенный',
'Class:UserRequest/Attribute:status/Value:resolved+' => '',
'Class:UserRequest/Attribute:status/Value:closed' => 'Закрыт',
'Class:UserRequest/Attribute:status/Value:closed+' => '',
'Class:UserRequest/Attribute:request_type' => 'Тип запроса',
'Class:UserRequest/Attribute:request_type+' => '',
'Class:UserRequest/Attribute:request_type/Value:service_request' => 'Запрос на обслуживание',
'Class:UserRequest/Attribute:request_type/Value:service_request+' => 'Запрос на обслуживание',
'Class:UserRequest/Attribute:impact' => 'Влияние',
'Class:UserRequest/Attribute:impact+' => '',
'Class:UserRequest/Attribute:impact/Value:1' => 'Департамент',
'Class:UserRequest/Attribute:impact/Value:1+' => '',
'Class:UserRequest/Attribute:impact/Value:2' => 'Служба',
'Class:UserRequest/Attribute:impact/Value:2+' => '',
'Class:UserRequest/Attribute:impact/Value:3' => 'Персона',
'Class:UserRequest/Attribute:impact/Value:3+' => '',
'Class:UserRequest/Attribute:priority' => 'Приоритет',
'Class:UserRequest/Attribute:priority+' => '',
'Class:UserRequest/Attribute:priority/Value:1' => 'Критический',
'Class:UserRequest/Attribute:priority/Value:1+' => 'Критический',
'Class:UserRequest/Attribute:priority/Value:2' => 'Высокий',
'Class:UserRequest/Attribute:priority/Value:2+' => 'Высокий',
'Class:UserRequest/Attribute:priority/Value:3' => 'Средний',
'Class:UserRequest/Attribute:priority/Value:3+' => 'Средний',
'Class:UserRequest/Attribute:priority/Value:4' => 'Низкий',
'Class:UserRequest/Attribute:priority/Value:4+' => 'Низкий',
'Class:UserRequest/Attribute:urgency' => 'Срочность',
'Class:UserRequest/Attribute:urgency+' => '',
'Class:UserRequest/Attribute:urgency/Value:1' => 'Критическая',
'Class:UserRequest/Attribute:urgency/Value:1+' => 'Критическая',
'Class:UserRequest/Attribute:urgency/Value:2' => 'Высокая',
'Class:UserRequest/Attribute:urgency/Value:2+' => 'Высокая',
'Class:UserRequest/Attribute:urgency/Value:3' => 'Средняя',
'Class:UserRequest/Attribute:urgency/Value:3+' => 'Средняя',
'Class:UserRequest/Attribute:urgency/Value:4' => 'Низкая',
'Class:UserRequest/Attribute:urgency/Value:4+' => 'Низкая',
'Class:UserRequest/Attribute:origin' => 'Источник',
'Class:UserRequest/Attribute:origin+' => '',
'Class:UserRequest/Attribute:origin/Value:mail' => 'Почта',
'Class:UserRequest/Attribute:origin/Value:mail+' => 'Почта',
'Class:UserRequest/Attribute:origin/Value:monitoring' => 'Мониторинг',
'Class:UserRequest/Attribute:origin/Value:monitoring+' => 'Мониторинг',
'Class:UserRequest/Attribute:origin/Value:phone' => 'Телефон',
'Class:UserRequest/Attribute:origin/Value:phone+' => 'Телефон',
'Class:UserRequest/Attribute:origin/Value:portal' => 'Портал',
'Class:UserRequest/Attribute:origin/Value:portal+' => 'Портал',
'Class:UserRequest/Attribute:approver_id' => 'Утверждающий',
'Class:UserRequest/Attribute:approver_id+' => '',
'Class:UserRequest/Attribute:approver_email' => 'Email утверждающего',
'Class:UserRequest/Attribute:approver_email+' => '',
'Class:UserRequest/Attribute:service_id' => 'Услуга',
'Class:UserRequest/Attribute:service_id+' => '',
'Class:UserRequest/Attribute:service_name' => 'Услуга',
'Class:UserRequest/Attribute:service_name+' => '',
'Class:UserRequest/Attribute:servicesubcategory_id' => 'Подкатегория',
'Class:UserRequest/Attribute:servicesubcategory_id+' => 'Подкатегория услуги',
'Class:UserRequest/Attribute:servicesubcategory_name' => 'Подкатегория услуги',
'Class:UserRequest/Attribute:servicesubcategory_name+' => '',
'Class:UserRequest/Attribute:escalation_flag' => 'Флаг эскалации',
'Class:UserRequest/Attribute:escalation_flag+' => '',
'Class:UserRequest/Attribute:escalation_flag/Value:no' => 'Нет',
'Class:UserRequest/Attribute:escalation_flag/Value:no+' => 'Нет',
'Class:UserRequest/Attribute:escalation_flag/Value:yes' => 'Да',
'Class:UserRequest/Attribute:escalation_flag/Value:yes+' => 'Да',
'Class:UserRequest/Attribute:escalation_reason' => 'Причина эскалации',
'Class:UserRequest/Attribute:escalation_reason+' => '',
'Class:UserRequest/Attribute:assignment_date' => 'Дата назначения',
'Class:UserRequest/Attribute:assignment_date+' => '',
'Class:UserRequest/Attribute:resolution_date' => 'Дата решения',
'Class:UserRequest/Attribute:resolution_date+' => '',
'Class:UserRequest/Attribute:last_pending_date' => 'Дата последнего ожидания',
'Class:UserRequest/Attribute:last_pending_date+' => '',
'Class:UserRequest/Attribute:cumulatedpending' => 'Накопленное ожидание',
'Class:UserRequest/Attribute:cumulatedpending+' => '',
'Class:UserRequest/Attribute:tto' => 'TTO',
'Class:UserRequest/Attribute:tto+' => '',
'Class:UserRequest/Attribute:ttr' => 'TTR',
'Class:UserRequest/Attribute:ttr+' => '',
'Class:UserRequest/Attribute:tto_escalation_deadline' => 'Срок TTO',
'Class:UserRequest/Attribute:tto_escalation_deadline+' => 'Крайний срок назаначения агента (принятия в работу) по текущему SLA',
'Class:UserRequest/Attribute:sla_tto_passed' => 'SLA TTO пропущено',
'Class:UserRequest/Attribute:sla_tto_passed+' => '',
'Class:UserRequest/Attribute:sla_tto_over' => 'SLA TTO превышено',
'Class:UserRequest/Attribute:sla_tto_over+' => '',
'Class:UserRequest/Attribute:ttr_escalation_deadline' => 'Срок TTR',
'Class:UserRequest/Attribute:ttr_escalation_deadline+' => 'Крайний срок решения по текущему SLA',
'Class:UserRequest/Attribute:sla_ttr_passed' => 'SLA TTR пропущено',
'Class:UserRequest/Attribute:sla_ttr_passed+' => '',
'Class:UserRequest/Attribute:sla_ttr_over' => 'SLA TTR превышено',
'Class:UserRequest/Attribute:sla_ttr_over+' => '',
'Class:UserRequest/Attribute:time_spent' => 'Время на решение',
'Class:UserRequest/Attribute:time_spent+' => '',
'Class:UserRequest/Attribute:resolution_code' => 'Код решения',
'Class:UserRequest/Attribute:resolution_code+' => '',
'Class:UserRequest/Attribute:resolution_code/Value:assistance' => 'Помощь',
'Class:UserRequest/Attribute:resolution_code/Value:assistance+' => 'Помощь',
'Class:UserRequest/Attribute:resolution_code/Value:bug fixed' => 'Исправление ошибки',
'Class:UserRequest/Attribute:resolution_code/Value:bug fixed+' => 'Исправление ошибки',
'Class:UserRequest/Attribute:resolution_code/Value:hardware repair' => 'Ремонт оборудования',
'Class:UserRequest/Attribute:resolution_code/Value:hardware repair+' => 'Ремонт оборудования',
'Class:UserRequest/Attribute:resolution_code/Value:other' => 'Другое',
'Class:UserRequest/Attribute:resolution_code/Value:other+' => 'Другое',
'Class:UserRequest/Attribute:resolution_code/Value:software patch' => 'Патч ПО',
'Class:UserRequest/Attribute:resolution_code/Value:software patch+' => 'Патч ПО',
'Class:UserRequest/Attribute:resolution_code/Value:system update' => 'Обновление системы',
'Class:UserRequest/Attribute:resolution_code/Value:system update+' => 'Обновление системы',
'Class:UserRequest/Attribute:resolution_code/Value:training' => 'Обучение',
'Class:UserRequest/Attribute:resolution_code/Value:training+' => 'Обучение',
'Class:UserRequest/Attribute:solution' => 'Описание решения',
'Class:UserRequest/Attribute:solution+' => '',
'Class:UserRequest/Attribute:pending_reason' => 'Причина ожидания',
'Class:UserRequest/Attribute:pending_reason+' => '',
'Class:UserRequest/Attribute:parent_request_id' => 'Родительский запрос',
'Class:UserRequest/Attribute:parent_request_id+' => '',
'Class:UserRequest/Attribute:parent_incident_id' => 'Родительский инцидент',
'Class:UserRequest/Attribute:parent_incident_id+' => '',
'Class:UserRequest/Attribute:parent_incident_ref' => 'Родительский инцидент',
'Class:UserRequest/Attribute:parent_incident_ref+' => '',
'Class:UserRequest/Attribute:parent_request_ref' => 'Родительский запрос',
'Class:UserRequest/Attribute:parent_request_ref+' => '',
'Class:UserRequest/Attribute:parent_problem_id' => 'Родительская проблема',
'Class:UserRequest/Attribute:parent_problem_id+' => '',
'Class:UserRequest/Attribute:parent_problem_ref' => 'Родительская проблема',
'Class:UserRequest/Attribute:parent_problem_ref+' => '',
'Class:UserRequest/Attribute:parent_change_id' => 'Родительское изменение',
'Class:UserRequest/Attribute:parent_change_id+' => '',
'Class:UserRequest/Attribute:parent_change_ref' => 'Родительское изменение',
'Class:UserRequest/Attribute:parent_change_ref+' => '',
'Class:UserRequest/Attribute:related_request_list' => 'Дочерние запросы',
'Class:UserRequest/Attribute:related_request_list+' => 'Дочерние запросы',
'Class:UserRequest/Attribute:public_log' => 'Общий журнал',
'Class:UserRequest/Attribute:public_log+' => 'Информация в общем журнале доступна для пользователей портала',
'Class:UserRequest/Attribute:user_satisfaction' => 'Удовлетворенность пользователя',
'Class:UserRequest/Attribute:user_satisfaction+' => '',
'Class:UserRequest/Attribute:user_satisfaction/Value:1' => 'Очень доволен',
'Class:UserRequest/Attribute:user_satisfaction/Value:1+' => 'Очень доволен',
'Class:UserRequest/Attribute:user_satisfaction/Value:2' => 'Вполне доволен',
'Class:UserRequest/Attribute:user_satisfaction/Value:2+' => 'Вполне доволен',
'Class:UserRequest/Attribute:user_satisfaction/Value:3' => 'Скорее недоволен',
'Class:UserRequest/Attribute:user_satisfaction/Value:3+' => 'Скорее недоволен',
'Class:UserRequest/Attribute:user_satisfaction/Value:4' => 'Очень недоволен',
'Class:UserRequest/Attribute:user_satisfaction/Value:4+' => 'Очень недоволен',
'Class:UserRequest/Attribute:user_comment' => 'Комментарий пользователя',
'Class:UserRequest/Attribute:user_comment+' => '',
'Class:UserRequest/Attribute:parent_request_id_friendlyname' => 'Родительский запрос',
'Class:UserRequest/Attribute:parent_request_id_friendlyname+' => '',
'Class:UserRequest/Stimulus:ev_assign' => 'Назначить',
'Class:UserRequest/Stimulus:ev_assign+' => '',
'Class:UserRequest/Stimulus:ev_reassign' => 'Переназначить',
'Class:UserRequest/Stimulus:ev_reassign+' => '',
'Class:UserRequest/Stimulus:ev_approve' => 'Утвердить',
'Class:UserRequest/Stimulus:ev_approve+' => '',
'Class:UserRequest/Stimulus:ev_reject' => 'Отклонить',
'Class:UserRequest/Stimulus:ev_reject+' => '',
'Class:UserRequest/Stimulus:ev_pending' => 'В ожидание',
'Class:UserRequest/Stimulus:ev_pending+' => '',
'Class:UserRequest/Stimulus:ev_timeout' => 'Таймаут',
'Class:UserRequest/Stimulus:ev_timeout+' => '',
'Class:UserRequest/Stimulus:ev_autoresolve' => 'Автоматическое решение',
'Class:UserRequest/Stimulus:ev_autoresolve+' => '',
'Class:UserRequest/Stimulus:ev_autoclose' => 'Автоматическое закрытие',
'Class:UserRequest/Stimulus:ev_autoclose+' => '',
'Class:UserRequest/Stimulus:ev_resolve' => 'Отметить как решенный',
'Class:UserRequest/Stimulus:ev_resolve+' => '',
'Class:UserRequest/Stimulus:ev_close' => 'Закрыть',
'Class:UserRequest/Stimulus:ev_close+' => '',
'Class:UserRequest/Stimulus:ev_reopen' => 'Вновь открыть',
'Class:UserRequest/Stimulus:ev_reopen+' => '',
'Class:UserRequest/Stimulus:ev_wait_for_approval' => 'Ждать утверждения',
'Class:UserRequest/Stimulus:ev_wait_for_approval+' => '',
'Class:UserRequest/Error:CannotAssignParentRequestIdToSelf' => 'Невозможно назначить этот же запрос в качестве родительского',
'Class:UserRequest/Method:ResolveChildTickets' => 'ResolveChildTickets',
'Class:UserRequest/Method:ResolveChildTickets+' => 'Cascade the resolution to child requests (ev_autoresolve), and align the following characteristics of the request: service, team, agent, resolution info',
));

View File

@@ -1338,7 +1338,7 @@
<code><![CDATA[ public function UpdateChildRequestLog()
{
$oLog = $this->Get('public_log');
$sLogPublic = $oLog->GetModifiedEntry('html');
$sLogPublic = $oLog->GetModifiedEntry();
if ($sLogPublic != '')
{
$sOQL = "SELECT UserRequest WHERE parent_request_id=:ticket";
@@ -1356,7 +1356,7 @@
}
$oLog = $this->Get('private_log');
$sLogPrivate = $oLog->GetModifiedEntry('html');
$sLogPrivate = $oLog->GetModifiedEntry();
if ($sLogPrivate != '')
{
$sOQL = "SELECT UserRequest WHERE parent_request_id=:ticket";

View File

@@ -1,284 +0,0 @@
<?php
/**
* Локализация интерфейса Combodo iTop подготовлена сообществом iTop по-русски http://community.itop-itsm.ru.
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @link http://community.itop-itsm.ru iTop Russian Community
* @link https://github.com/itop-itsm-ru/itop-rus
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*
*/
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Menu:RequestManagement' => 'Helpdesk',
'Menu:RequestManagement+' => 'Helpdesk',
'Menu:RequestManagementProvider' => 'Поставщик техподдержки',
'Menu:RequestManagementProvider+' => 'Поставщик техподдержки',
'Menu:UserRequest:Provider' => 'Открытые запросы, отправленные поставщику',
'Menu:UserRequest:Provider+' => 'Открытые запросы, отправленные поставщику',
'Menu:UserRequest:Overview' => 'Обзор',
'Menu:UserRequest:Overview+' => 'Обзор',
'Menu:NewUserRequest' => 'Новый запрос',
'Menu:NewUserRequest+' => 'Создать новый запрос на обслуживание',
'Menu:SearchUserRequests' => 'Поиск запросов',
'Menu:SearchUserRequests+' => 'Поиск запросов на обслуживание',
'Menu:UserRequest:Shortcuts' => 'Ярлыки',
'Menu:UserRequest:Shortcuts+' => 'Ярлыки',
'Menu:UserRequest:MyRequests' => 'Назначенные мне',
'Menu:UserRequest:MyRequests+' => 'Назначенные мне (в качестве агента)',
'Menu:UserRequest:MySupportRequests' => "Созданные мной",
'Menu:UserRequest:MySupportRequests+' => "Созданные мной запросы",
'Menu:UserRequest:EscalatedRequests' => 'Эскалированные',
'Menu:UserRequest:EscalatedRequests+' => 'Эскалированные запросы',
'Menu:UserRequest:OpenRequests' => 'Открытые',
'Menu:UserRequest:OpenRequests+' => 'Открытые запросы',
'UI:WelcomeMenu:MyAssignedCalls' => 'Назначенные мне запросы',
'UI-RequestManagementOverview-RequestByType-last-14-days' => 'Запросы по типу за 14 дней',
'UI-RequestManagementOverview-Last-14-days' => 'Количество запросов за 14 дней',
'UI-RequestManagementOverview-OpenRequestByStatus' => 'Открытые запросы по статусу',
'UI-RequestManagementOverview-OpenRequestByAgent' => 'Открытые запросы по агенту',
'UI-RequestManagementOverview-OpenRequestByType' => 'Открытые запросы по типу',
'UI-RequestManagementOverview-OpenRequestByCustomer' => 'Открытые запросы по заказчику',
'Class:UserRequest:KnownErrorList' => 'Известные ошибки',
'Menu:UserRequest:MyWorkOrders' => 'Назначенные мне наряды на работу',
'Menu:UserRequest:MyWorkOrders+' => 'Назначенные мне наряды на работу',
'Class:Problem:KnownProblemList' => 'Известные проблемы',
'Tickets:Related:OpenIncidents' => 'Открытые инциденты',
));
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: UserRequest
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:UserRequest' => 'Запрос',
'Class:UserRequest+' => '',
'Class:UserRequest/Attribute:status' => 'Статус',
'Class:UserRequest/Attribute:status+' => '',
'Class:UserRequest/Attribute:status/Value:new' => 'Новый',
'Class:UserRequest/Attribute:status/Value:new+' => '',
'Class:UserRequest/Attribute:status/Value:escalated_tto' => 'Эскалация TTO',
'Class:UserRequest/Attribute:status/Value:escalated_tto+' => '',
'Class:UserRequest/Attribute:status/Value:assigned' => 'Назначен',
'Class:UserRequest/Attribute:status/Value:assigned+' => '',
'Class:UserRequest/Attribute:status/Value:escalated_ttr' => 'Эскалация TTR',
'Class:UserRequest/Attribute:status/Value:escalated_ttr+' => '',
'Class:UserRequest/Attribute:status/Value:waiting_for_approval' => 'Ожидание утверждения',
'Class:UserRequest/Attribute:status/Value:waiting_for_approval+' => '',
'Class:UserRequest/Attribute:status/Value:approved' => 'Утвержден',
'Class:UserRequest/Attribute:status/Value:approved+' => '',
'Class:UserRequest/Attribute:status/Value:rejected' => 'Отклонен',
'Class:UserRequest/Attribute:status/Value:rejected+' => '',
'Class:UserRequest/Attribute:status/Value:pending' => 'В ожидании',
'Class:UserRequest/Attribute:status/Value:pending+' => '',
'Class:UserRequest/Attribute:status/Value:resolved' => 'Решенный',
'Class:UserRequest/Attribute:status/Value:resolved+' => '',
'Class:UserRequest/Attribute:status/Value:closed' => 'Закрыт',
'Class:UserRequest/Attribute:status/Value:closed+' => '',
'Class:UserRequest/Attribute:request_type' => 'Тип запроса',
'Class:UserRequest/Attribute:request_type+' => '',
'Class:UserRequest/Attribute:request_type/Value:incident' => 'Инцидент',
'Class:UserRequest/Attribute:request_type/Value:incident+' => 'Инцидент',
'Class:UserRequest/Attribute:request_type/Value:service_request' => 'Запрос на обслуживание',
'Class:UserRequest/Attribute:request_type/Value:service_request+' => 'Запрос на обслуживание',
'Class:UserRequest/Attribute:impact' => 'Влияние',
'Class:UserRequest/Attribute:impact+' => '',
'Class:UserRequest/Attribute:impact/Value:1' => 'Департамент',
'Class:UserRequest/Attribute:impact/Value:1+' => '',
'Class:UserRequest/Attribute:impact/Value:2' => 'Служба',
'Class:UserRequest/Attribute:impact/Value:2+' => '',
'Class:UserRequest/Attribute:impact/Value:3' => 'Персона',
'Class:UserRequest/Attribute:impact/Value:3+' => '',
'Class:UserRequest/Attribute:priority' => 'Приоритет',
'Class:UserRequest/Attribute:priority+' => '',
'Class:UserRequest/Attribute:priority/Value:1' => 'Критический',
'Class:UserRequest/Attribute:priority/Value:1+' => 'Критический',
'Class:UserRequest/Attribute:priority/Value:2' => 'Высокий',
'Class:UserRequest/Attribute:priority/Value:2+' => 'Высокий',
'Class:UserRequest/Attribute:priority/Value:3' => 'Средний',
'Class:UserRequest/Attribute:priority/Value:3+' => 'Средний',
'Class:UserRequest/Attribute:priority/Value:4' => 'Низкий',
'Class:UserRequest/Attribute:priority/Value:4+' => 'Низкий',
'Class:UserRequest/Attribute:urgency' => 'Срочность',
'Class:UserRequest/Attribute:urgency+' => '',
'Class:UserRequest/Attribute:urgency/Value:1' => 'Критическая',
'Class:UserRequest/Attribute:urgency/Value:1+' => 'Критическая',
'Class:UserRequest/Attribute:urgency/Value:2' => 'Высокая',
'Class:UserRequest/Attribute:urgency/Value:2+' => 'Высокая',
'Class:UserRequest/Attribute:urgency/Value:3' => 'Средняя',
'Class:UserRequest/Attribute:urgency/Value:3+' => 'Средняя',
'Class:UserRequest/Attribute:urgency/Value:4' => 'Низкая',
'Class:UserRequest/Attribute:urgency/Value:4+' => 'Низкая',
'Class:UserRequest/Attribute:origin' => 'Источник',
'Class:UserRequest/Attribute:origin+' => '',
'Class:UserRequest/Attribute:origin/Value:mail' => 'Почта',
'Class:UserRequest/Attribute:origin/Value:mail+' => 'Почта',
'Class:UserRequest/Attribute:origin/Value:monitoring' => 'Мониторинг',
'Class:UserRequest/Attribute:origin/Value:monitoring+' => 'Мониторинг',
'Class:UserRequest/Attribute:origin/Value:phone' => 'Телефон',
'Class:UserRequest/Attribute:origin/Value:phone+' => 'Телефон',
'Class:UserRequest/Attribute:origin/Value:portal' => 'Портал',
'Class:UserRequest/Attribute:origin/Value:portal+' => 'Портал',
'Class:UserRequest/Attribute:approver_id' => 'Утверждающий',
'Class:UserRequest/Attribute:approver_id+' => '',
'Class:UserRequest/Attribute:approver_email' => 'Email утверждающего',
'Class:UserRequest/Attribute:approver_email+' => '',
'Class:UserRequest/Attribute:service_id' => 'Услуга',
'Class:UserRequest/Attribute:service_id+' => '',
'Class:UserRequest/Attribute:service_name' => 'Услуга',
'Class:UserRequest/Attribute:service_name+' => '',
'Class:UserRequest/Attribute:servicesubcategory_id' => 'Подкатегория',
'Class:UserRequest/Attribute:servicesubcategory_id+' => 'Подкатегория услуги',
'Class:UserRequest/Attribute:servicesubcategory_name' => 'Подкатегория услуги',
'Class:UserRequest/Attribute:servicesubcategory_name+' => '',
'Class:UserRequest/Attribute:escalation_flag' => 'Флаг эскалации',
'Class:UserRequest/Attribute:escalation_flag+' => '',
'Class:UserRequest/Attribute:escalation_flag/Value:no' => 'Нет',
'Class:UserRequest/Attribute:escalation_flag/Value:no+' => 'Нет',
'Class:UserRequest/Attribute:escalation_flag/Value:yes' => 'Да',
'Class:UserRequest/Attribute:escalation_flag/Value:yes+' => 'Да',
'Class:UserRequest/Attribute:escalation_reason' => 'Причина эскалации',
'Class:UserRequest/Attribute:escalation_reason+' => '',
'Class:UserRequest/Attribute:assignment_date' => 'Дата назначения',
'Class:UserRequest/Attribute:assignment_date+' => '',
'Class:UserRequest/Attribute:resolution_date' => 'Дата решения',
'Class:UserRequest/Attribute:resolution_date+' => '',
'Class:UserRequest/Attribute:last_pending_date' => 'Дата последнего ожидания',
'Class:UserRequest/Attribute:last_pending_date+' => '',
'Class:UserRequest/Attribute:cumulatedpending' => 'Накопленное ожидание',
'Class:UserRequest/Attribute:cumulatedpending+' => '',
'Class:UserRequest/Attribute:tto' => 'TTO',
'Class:UserRequest/Attribute:tto+' => '',
'Class:UserRequest/Attribute:ttr' => 'TTR',
'Class:UserRequest/Attribute:ttr+' => '',
'Class:UserRequest/Attribute:tto_escalation_deadline' => 'Срок TTO',
'Class:UserRequest/Attribute:tto_escalation_deadline+' => 'Крайний срок назаначения агента (принятия в работу) по текущему SLA',
'Class:UserRequest/Attribute:sla_tto_passed' => 'SLA TTO пропущено',
'Class:UserRequest/Attribute:sla_tto_passed+' => '',
'Class:UserRequest/Attribute:sla_tto_over' => 'SLA TTO превышено',
'Class:UserRequest/Attribute:sla_tto_over+' => '',
'Class:UserRequest/Attribute:ttr_escalation_deadline' => 'Срок TTR',
'Class:UserRequest/Attribute:ttr_escalation_deadline+' => 'Крайний срок решения по текущему SLA',
'Class:UserRequest/Attribute:sla_ttr_passed' => 'SLA TTR пропущено',
'Class:UserRequest/Attribute:sla_ttr_passed+' => '',
'Class:UserRequest/Attribute:sla_ttr_over' => 'SLA TTR превышено',
'Class:UserRequest/Attribute:sla_ttr_over+' => '',
'Class:UserRequest/Attribute:time_spent' => 'Время на решение',
'Class:UserRequest/Attribute:time_spent+' => '',
'Class:UserRequest/Attribute:resolution_code' => 'Код решения',
'Class:UserRequest/Attribute:resolution_code+' => '',
'Class:UserRequest/Attribute:resolution_code/Value:assistance' => 'Помощь',
'Class:UserRequest/Attribute:resolution_code/Value:assistance+' => 'Помощь',
'Class:UserRequest/Attribute:resolution_code/Value:bug fixed' => 'Исправление ошибки',
'Class:UserRequest/Attribute:resolution_code/Value:bug fixed+' => 'Исправление ошибки',
'Class:UserRequest/Attribute:resolution_code/Value:hardware repair' => 'Ремонт оборудования',
'Class:UserRequest/Attribute:resolution_code/Value:hardware repair+' => 'Ремонт оборудования',
'Class:UserRequest/Attribute:resolution_code/Value:other' => 'Другое',
'Class:UserRequest/Attribute:resolution_code/Value:other+' => 'Другое',
'Class:UserRequest/Attribute:resolution_code/Value:software patch' => 'Патч ПО',
'Class:UserRequest/Attribute:resolution_code/Value:software patch+' => 'Патч ПО',
'Class:UserRequest/Attribute:resolution_code/Value:system update' => 'Обновление системы',
'Class:UserRequest/Attribute:resolution_code/Value:system update+' => 'Обновление системы',
'Class:UserRequest/Attribute:resolution_code/Value:training' => 'Обучение',
'Class:UserRequest/Attribute:resolution_code/Value:training+' => 'Обучение',
'Class:UserRequest/Attribute:solution' => 'Описание решения',
'Class:UserRequest/Attribute:solution+' => '',
'Class:UserRequest/Attribute:pending_reason' => 'Причина ожидания',
'Class:UserRequest/Attribute:pending_reason+' => '',
'Class:UserRequest/Attribute:parent_request_id' => 'Родительский запрос',
'Class:UserRequest/Attribute:parent_request_id+' => '',
'Class:UserRequest/Attribute:parent_request_ref' => 'Родительский запрос',
'Class:UserRequest/Attribute:parent_request_ref+' => '',
'Class:UserRequest/Attribute:parent_problem_id' => 'Родительская проблема',
'Class:UserRequest/Attribute:parent_problem_id+' => '',
'Class:UserRequest/Attribute:parent_problem_ref' => 'Родительская проблема',
'Class:UserRequest/Attribute:parent_problem_ref+' => '',
'Class:UserRequest/Attribute:parent_change_id' => 'Родительское изменение',
'Class:UserRequest/Attribute:parent_change_id+' => '',
'Class:UserRequest/Attribute:parent_change_ref' => 'Родительское изменение',
'Class:UserRequest/Attribute:parent_change_ref+' => '',
'Class:UserRequest/Attribute:related_request_list' => 'Дочерние запросы',
'Class:UserRequest/Attribute:related_request_list+' => 'Дочерние запросы',
'Class:UserRequest/Attribute:public_log' => 'Общий журнал',
'Class:UserRequest/Attribute:public_log+' => 'Информация в общем журнале доступна для пользователей портала',
'Class:UserRequest/Attribute:user_satisfaction' => 'Удовлетворенность пользователя',
'Class:UserRequest/Attribute:user_satisfaction+' => '',
'Class:UserRequest/Attribute:user_satisfaction/Value:1' => 'Очень доволен',
'Class:UserRequest/Attribute:user_satisfaction/Value:1+' => 'Очень доволен',
'Class:UserRequest/Attribute:user_satisfaction/Value:2' => 'Вполне доволен',
'Class:UserRequest/Attribute:user_satisfaction/Value:2+' => 'Вполне доволен',
'Class:UserRequest/Attribute:user_satisfaction/Value:3' => 'Скорее недоволен',
'Class:UserRequest/Attribute:user_satisfaction/Value:3+' => 'Скорее недоволен',
'Class:UserRequest/Attribute:user_satisfaction/Value:4' => 'Очень недоволен',
'Class:UserRequest/Attribute:user_satisfaction/Value:4+' => 'Очень недоволен',
'Class:UserRequest/Attribute:user_comment' => 'Комментарий пользователя',
'Class:UserRequest/Attribute:user_comment+' => '',
'Class:UserRequest/Attribute:parent_request_id_friendlyname' => 'Родительский запрос',
'Class:UserRequest/Attribute:parent_request_id_friendlyname+' => '',
'Class:UserRequest/Stimulus:ev_assign' => 'Назначить',
'Class:UserRequest/Stimulus:ev_assign+' => '',
'Class:UserRequest/Stimulus:ev_reassign' => 'Переназначить',
'Class:UserRequest/Stimulus:ev_reassign+' => '',
'Class:UserRequest/Stimulus:ev_approve' => 'Утвердить',
'Class:UserRequest/Stimulus:ev_approve+' => '',
'Class:UserRequest/Stimulus:ev_reject' => 'Отклонить',
'Class:UserRequest/Stimulus:ev_reject+' => '',
'Class:UserRequest/Stimulus:ev_pending' => 'В ожидание',
'Class:UserRequest/Stimulus:ev_pending+' => '',
'Class:UserRequest/Stimulus:ev_timeout' => 'Таймаут',
'Class:UserRequest/Stimulus:ev_timeout+' => '',
'Class:UserRequest/Stimulus:ev_autoresolve' => 'Автоматическое решение',
'Class:UserRequest/Stimulus:ev_autoresolve+' => '',
'Class:UserRequest/Stimulus:ev_autoclose' => 'Автоматическое закрытие',
'Class:UserRequest/Stimulus:ev_autoclose+' => '',
'Class:UserRequest/Stimulus:ev_resolve' => 'Отметить как решенный',
'Class:UserRequest/Stimulus:ev_resolve+' => '',
'Class:UserRequest/Stimulus:ev_close' => 'Закрыть',
'Class:UserRequest/Stimulus:ev_close+' => '',
'Class:UserRequest/Stimulus:ev_reopen' => 'Вновь открыть',
'Class:UserRequest/Stimulus:ev_reopen+' => '',
'Class:UserRequest/Stimulus:ev_wait_for_approval' => 'Ждать утверждения',
'Class:UserRequest/Stimulus:ev_wait_for_approval+' => '',
'Class:UserRequest/Error:CannotAssignParentRequestIdToSelf' => 'Невозможно назначить этот же запрос в качестве родительского',
));
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Portal:TitleDetailsFor_Request' => 'Детали запроса',
'Portal:ButtonUpdate' => 'Обновить',
'Portal:ButtonClose' => 'Закрыть',
'Portal:ButtonReopen' => 'Открыть вновь',
'Portal:ShowServices' => 'Каталог услуг',
'Portal:SelectRequestType' => 'Выберите тип запроса',
'Portal:SelectServiceElementFrom_Service' => 'Выберите элемент услуги для %1$s',
'Portal:SelectRequestTemplate' => 'Выберите шаблон для %1$s',
'Portal:ListServices' => 'Список услуг',
'Portal:TitleDetailsFor_Service' => 'Детали услуги',
'Portal:Button:CreateRequestFromService' => 'Создать запрос по услуге',
'Portal:ListOpenRequests' => 'Открытые запросы',
'Portal:UserRequest:MoreInfo' => 'Дополнительная информация',
'Portal:Details-Service-Element' => 'Элементы услуги',
'Portal:NoClosedTicket' => 'Нет закрытых запросов',
'Portal:NoService' => '',
'Portal:ListOpenProblems' => 'Открытые проблемы',
'Portal:ShowProblem' => 'Проблемы',
'Portal:ShowFaqs' => 'FAQ',
'Portal:NoOpenProblem' => 'Нет открытых проблем',
'Portal:SelectLanguage' => "Изменить язык",
'Portal:LanguageChangedTo_Lang' => 'Язык изменен на',
'Portal:ChooseYourFavoriteLanguage' => 'Выберите язык',
'Class:UserRequest/Method:ResolveChildTickets' => 'ResolveChildTickets',
'Class:UserRequest/Method:ResolveChildTickets+' => 'Cascade the resolution to child requests (ev_autoresolve), and align the following characteristics of the request: service, team, agent, resolution info',
));

View File

@@ -1,494 +0,0 @@
<?php
/**
* Локализация интерфейса Combodo iTop подготовлена сообществом iTop по-русски http://community.itop-itsm.ru.
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @link http://community.itop-itsm.ru iTop Russian Community
* @link https://github.com/itop-itsm-ru/itop-rus
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*
*/
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Menu:ServiceManagement' => 'Управление услугами',
'Menu:ServiceManagement+' => 'Управление услугами',
'Menu:Service:Overview' => 'Обзор',
'Menu:Service:Overview+' => 'Управление услугами - Обзор',
'UI-ServiceManagementMenu-ContractsBySrvLevel' => 'Договоры по уровню услуги',
'UI-ServiceManagementMenu-ContractsByStatus' => 'Договоры по статусу',
'UI-ServiceManagementMenu-ContractsEndingIn30Days' => 'Договоры, оканчивающиеся в течение 30-ти дней',
'Menu:ProviderContract' => 'Договоры с поставщиками',
'Menu:ProviderContract+' => 'Договоры с поставщиками',
'Menu:CustomerContract' => 'Договоры с заказчиками',
'Menu:CustomerContract+' => 'Договоры с заказчиками',
'Menu:ServiceSubcategory' => 'Подкатегории услуг',
'Menu:ServiceSubcategory+' => 'Подкатегории услуг',
'Menu:Service' => 'Услуги',
'Menu:Service+' => 'Услуги',
'Menu:ServiceElement' => 'Элементы услуг',
'Menu:ServiceElement+' => 'Элементы услуг',
'Menu:SLA' => 'SLA',
'Menu:SLA+' => 'Соглашения об уровне услуг',
'Menu:SLT' => 'SLT',
'Menu:SLT+' => 'Целевые показатели уровня услуг',
'Menu:DeliveryModel' => 'Модели предоставления услуг',
'Menu:DeliveryModel+' => 'Модели предоставления услуг (Delivery Models)',
));
//
// Class: Organization
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Organization/Attribute:deliverymodel_id' => 'Модель предоставления услуг',
'Class:Organization/Attribute:deliverymodel_id+' => 'Модель предоставления услуг (Delivery Model)',
'Class:Organization/Attribute:deliverymodel_name' => 'Модель предоставления услуг',
'Class:Organization/Attribute:deliverymodel_name+' => '',
));
//
// Class: ContractType
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:ContractType' => 'Тип договора',
'Class:ContractType+' => '',
));
//
// Class: Contract
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Contract' => 'Договор',
'Class:Contract+' => '',
'Class:Contract/Attribute:name' => 'Название',
'Class:Contract/Attribute:name+' => '',
'Class:Contract/Attribute:org_id' => 'Заказчик',
'Class:Contract/Attribute:org_id+' => '',
'Class:Contract/Attribute:organization_name' => 'Заказчик',
'Class:Contract/Attribute:organization_name+' => '',
'Class:Contract/Attribute:contacts_list' => 'Контакты',
'Class:Contract/Attribute:contacts_list+' => 'Связанные контакты',
'Class:Contract/Attribute:documents_list' => 'Документы',
'Class:Contract/Attribute:documents_list+' => 'Связанные документы',
'Class:Contract/Attribute:description' => 'Описание',
'Class:Contract/Attribute:description+' => '',
'Class:Contract/Attribute:start_date' => 'Дата начала',
'Class:Contract/Attribute:start_date+' => '',
'Class:Contract/Attribute:end_date' => 'Дата окончания',
'Class:Contract/Attribute:end_date+' => '',
'Class:Contract/Attribute:cost' => 'Стоимость',
'Class:Contract/Attribute:cost+' => '',
'Class:Contract/Attribute:cost_currency' => 'Валюта стоимости',
'Class:Contract/Attribute:cost_currency+' => '',
'Class:Contract/Attribute:cost_currency/Value:dollars' => 'Доллары',
'Class:Contract/Attribute:cost_currency/Value:dollars+' => '',
'Class:Contract/Attribute:cost_currency/Value:euros' => 'Евро',
'Class:Contract/Attribute:cost_currency/Value:euros+' => '',
'Class:Contract/Attribute:contracttype_id' => 'Тип договора',
'Class:Contract/Attribute:contracttype_id+' => '',
'Class:Contract/Attribute:contracttype_name' => 'Тип договора',
'Class:Contract/Attribute:contracttype_name+' => '',
'Class:Contract/Attribute:billing_frequency' => 'Периодичность платежей',
'Class:Contract/Attribute:billing_frequency+' => '',
'Class:Contract/Attribute:cost_unit' => 'Единица стоимости',
'Class:Contract/Attribute:cost_unit+' => '',
'Class:Contract/Attribute:provider_id' => 'Поставщик',
'Class:Contract/Attribute:provider_id+' => '',
'Class:Contract/Attribute:provider_name' => 'Поставщик',
'Class:Contract/Attribute:provider_name+' => '',
'Class:Contract/Attribute:status' => 'Статус',
'Class:Contract/Attribute:status+' => '',
'Class:Contract/Attribute:status/Value:implementation' => 'Внедрение',
'Class:Contract/Attribute:status/Value:implementation+' => 'Внедрение',
'Class:Contract/Attribute:status/Value:obsolete' => 'Устаревшее',
'Class:Contract/Attribute:status/Value:obsolete+' => 'Устаревшее',
'Class:Contract/Attribute:status/Value:production' => 'Эксплуатация',
'Class:Contract/Attribute:status/Value:production+' => 'Эксплуатация',
'Class:Contract/Attribute:finalclass' => 'Тип',
'Class:Contract/Attribute:finalclass+' => '',
));
//
// Class: CustomerContract
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:CustomerContract' => 'Договор с заказчиком',
'Class:CustomerContract+' => '',
'Class:CustomerContract/Attribute:services_list' => 'Услуги',
'Class:CustomerContract/Attribute:services_list+' => 'Все услуги, предоставляемые по договору',
'Class:CustomerContract/Attribute:functionalcis_list' => 'КЕ',
'Class:CustomerContract/Attribute:functionalcis_list+' => 'Конфигурационные единицы, охватываемые договором',
'Class:CustomerContract/Attribute:providercontracts_list' => 'Договоры с поставщиками',
'Class:CustomerContract/Attribute:providercontracts_list+' => 'Договоры с поставщиками, используемые для поддержки услуг данного договора (Underpinning Contracts)',
));
//
// Class: ProviderContract
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:ProviderContract' => 'Договор с поставщиком',
'Class:ProviderContract+' => '',
'Class:ProviderContract/Attribute:functionalcis_list' => 'КЕ',
'Class:ProviderContract/Attribute:functionalcis_list+' => 'Конфигурационные единицы, охватываемые договором',
'Class:ProviderContract/Attribute:sla' => 'SLA',
'Class:ProviderContract/Attribute:sla+' => 'Соглашение об уровне услуги (Service Level Agreement)',
'Class:ProviderContract/Attribute:coverage' => 'Время обслуживания',
'Class:ProviderContract/Attribute:coverage+' => '',
));
//
// Class: lnkContactToContract
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkContactToContract' => 'Связь Контакт/Договор',
'Class:lnkContactToContract+' => '',
'Class:lnkContactToContract/Attribute:contract_id' => 'Договор',
'Class:lnkContactToContract/Attribute:contract_id+' => '',
'Class:lnkContactToContract/Attribute:contract_name' => 'Договор',
'Class:lnkContactToContract/Attribute:contract_name+' => '',
'Class:lnkContactToContract/Attribute:contact_id' => 'Контакт',
'Class:lnkContactToContract/Attribute:contact_id+' => '',
'Class:lnkContactToContract/Attribute:contact_name' => 'Контакт',
'Class:lnkContactToContract/Attribute:contact_name+' => '',
));
//
// Class: lnkContractToDocument
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkContractToDocument' => 'Связь Договор/Документ',
'Class:lnkContractToDocument+' => '',
'Class:lnkContractToDocument/Attribute:contract_id' => 'Договор',
'Class:lnkContractToDocument/Attribute:contract_id+' => '',
'Class:lnkContractToDocument/Attribute:contract_name' => 'Договор',
'Class:lnkContractToDocument/Attribute:contract_name+' => '',
'Class:lnkContractToDocument/Attribute:document_id' => 'Документ',
'Class:lnkContractToDocument/Attribute:document_id+' => '',
'Class:lnkContractToDocument/Attribute:document_name' => 'Документ',
'Class:lnkContractToDocument/Attribute:document_name+' => '',
));
//
// Class: lnkFunctionalCIToProviderContract
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkFunctionalCIToProviderContract' => 'Связь Функциональная КЕ/Договор с поставщиком',
'Class:lnkFunctionalCIToProviderContract+' => '',
'Class:lnkFunctionalCIToProviderContract/Attribute:providercontract_id' => 'Договор с поставщиком',
'Class:lnkFunctionalCIToProviderContract/Attribute:providercontract_id+' => '',
'Class:lnkFunctionalCIToProviderContract/Attribute:providercontract_name' => 'Договор с поставщиком',
'Class:lnkFunctionalCIToProviderContract/Attribute:providercontract_name+' => '',
'Class:lnkFunctionalCIToProviderContract/Attribute:functionalci_id' => 'КЕ',
'Class:lnkFunctionalCIToProviderContract/Attribute:functionalci_id+' => '',
'Class:lnkFunctionalCIToProviderContract/Attribute:functionalci_name' => 'КЕ',
'Class:lnkFunctionalCIToProviderContract/Attribute:functionalci_name+' => '',
));
//
// Class: ServiceFamily
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:ServiceFamily' => 'Пакет услуг',
'Class:ServiceFamily+' => '',
'Class:ServiceFamily/Attribute:name' => 'Название',
'Class:ServiceFamily/Attribute:name+' => '',
'Class:ServiceFamily/Attribute:services_list' => 'Услуги',
'Class:ServiceFamily/Attribute:services_list+' => 'Связанные услуги',
));
//
// Class: Service
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Service' => 'Услуга',
'Class:Service+' => '',
'Class:Service/Attribute:name' => 'Название',
'Class:Service/Attribute:name+' => '',
'Class:Service/Attribute:org_id' => 'Поставщик',
'Class:Service/Attribute:org_id+' => '',
'Class:Service/Attribute:organization_name' => 'Поставщик',
'Class:Service/Attribute:organization_name+' => '',
'Class:Service/Attribute:description' => 'Описание',
'Class:Service/Attribute:description+' => '',
'Class:Service/Attribute:servicefamily_id' => 'Пакет услуг',
'Class:Service/Attribute:servicefamily_id+' => '',
'Class:Service/Attribute:servicefamily_name' => 'Пакет услуг',
'Class:Service/Attribute:servicefamily_name+' => '',
'Class:Service/Attribute:documents_list' => 'Документы',
'Class:Service/Attribute:documents_list+' => 'Связанные документы',
'Class:Service/Attribute:contacts_list' => 'Контакты',
'Class:Service/Attribute:contacts_list+' => 'Связанные контакты',
'Class:Service/Attribute:status' => 'Статус',
'Class:Service/Attribute:status+' => '',
'Class:Service/Attribute:status/Value:implementation' => 'Внедрение',
'Class:Service/Attribute:status/Value:implementation+' => 'Внедрение',
'Class:Service/Attribute:status/Value:obsolete' => 'Устаревшее',
'Class:Service/Attribute:status/Value:obsolete+' => 'Устаревшее',
'Class:Service/Attribute:status/Value:production' => 'Эксплуатация',
'Class:Service/Attribute:status/Value:production+' => 'Эксплуатация',
'Class:Service/Attribute:customercontracts_list' => 'Договоры с заказчиками',
'Class:Service/Attribute:customercontracts_list+' => 'Договоры с заказчиками, по которым предоставляется услуга',
'Class:Service/Attribute:servicesubcategories_list' => 'Подкатегории услуги',
'Class:Service/Attribute:servicesubcategories_list+' => 'Подкатегории услуги',
));
//
// Class: lnkDocumentToService
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkDocumentToService' => 'Связь Документ/Услуга',
'Class:lnkDocumentToService+' => '',
'Class:lnkDocumentToService/Attribute:service_id' => 'Услуга',
'Class:lnkDocumentToService/Attribute:service_id+' => '',
'Class:lnkDocumentToService/Attribute:service_name' => 'Услуга',
'Class:lnkDocumentToService/Attribute:service_name+' => '',
'Class:lnkDocumentToService/Attribute:document_id' => 'Документ',
'Class:lnkDocumentToService/Attribute:document_id+' => '',
'Class:lnkDocumentToService/Attribute:document_name' => 'Документ',
'Class:lnkDocumentToService/Attribute:document_name+' => '',
));
//
// Class: lnkContactToService
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkContactToService' => 'Связь Контакт/Услуга',
'Class:lnkContactToService+' => '',
'Class:lnkContactToService/Attribute:service_id' => 'Услуга',
'Class:lnkContactToService/Attribute:service_id+' => '',
'Class:lnkContactToService/Attribute:service_name' => 'Услуга',
'Class:lnkContactToService/Attribute:service_name+' => '',
'Class:lnkContactToService/Attribute:contact_id' => 'Контакт',
'Class:lnkContactToService/Attribute:contact_id+' => '',
'Class:lnkContactToService/Attribute:contact_name' => 'Контакт',
'Class:lnkContactToService/Attribute:contact_name+' => '',
));
//
// Class: ServiceSubcategory
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:ServiceSubcategory' => 'Подкатегория услуги',
'Class:ServiceSubcategory+' => '',
'Class:ServiceSubcategory/Attribute:name' => 'Название',
'Class:ServiceSubcategory/Attribute:name+' => '',
'Class:ServiceSubcategory/Attribute:description' => 'Описание',
'Class:ServiceSubcategory/Attribute:description+' => '',
'Class:ServiceSubcategory/Attribute:service_id' => 'Услуга',
'Class:ServiceSubcategory/Attribute:service_id+' => '',
'Class:ServiceSubcategory/Attribute:service_name' => 'Услуга',
'Class:ServiceSubcategory/Attribute:service_name+' => '',
'Class:ServiceSubcategory/Attribute:status' => 'Статус',
'Class:ServiceSubcategory/Attribute:status+' => '',
'Class:ServiceSubcategory/Attribute:status/Value:implementation' => 'Внедрение',
'Class:ServiceSubcategory/Attribute:status/Value:implementation+' => 'Внедрение',
'Class:ServiceSubcategory/Attribute:status/Value:obsolete' => 'Устаревшее',
'Class:ServiceSubcategory/Attribute:status/Value:obsolete+' => 'Устаревшее',
'Class:ServiceSubcategory/Attribute:status/Value:production' => 'Эксплуатация',
'Class:ServiceSubcategory/Attribute:status/Value:production+' => 'Эксплуатация',
'Class:ServiceSubcategory/Attribute:request_type' => 'Тип запроса',
'Class:ServiceSubcategory/Attribute:request_type+' => '',
'Class:ServiceSubcategory/Attribute:request_type/Value:incident' => 'Инцидент',
'Class:ServiceSubcategory/Attribute:request_type/Value:incident+' => 'Инцидент',
'Class:ServiceSubcategory/Attribute:request_type/Value:service_request' => 'Запрос на обслуживание',
'Class:ServiceSubcategory/Attribute:request_type/Value:service_request+' => 'Запрос на обслуживание',
'Class:ServiceSubcategory/Attribute:service_provider' => 'Поставщик',
'Class:ServiceSubcategory/Attribute:service_org_id' => 'Поставщик',
));
//
// Class: SLA
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:SLA' => 'SLA',
'Class:SLA+' => '',
'Class:SLA/Attribute:name' => 'Название',
'Class:SLA/Attribute:name+' => '',
'Class:SLA/Attribute:description' => 'Описание',
'Class:SLA/Attribute:description+' => '',
'Class:SLA/Attribute:org_id' => 'Организация',
'Class:SLA/Attribute:org_id+' => '',
'Class:SLA/Attribute:organization_name' => 'Организация',
'Class:SLA/Attribute:organization_name+' => '',
'Class:SLA/Attribute:slts_list' => 'SLT',
'Class:SLA/Attribute:slts_list+' => 'Целевой показатель уровня услуги (Service Level Target)',
'Class:SLA/Attribute:customercontracts_list' => 'Договоры с заказчиками',
'Class:SLA/Attribute:customercontracts_list+' => 'Договоры с заказчиками, в которых используется SLA',
));
//
// Class: SLT
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:SLT' => 'SLT',
'Class:SLT+' => '',
'Class:SLT/Attribute:name' => 'Название',
'Class:SLT/Attribute:name+' => '',
'Class:SLT/Attribute:priority' => 'Приоритет',
'Class:SLT/Attribute:priority+' => '',
'Class:SLT/Attribute:priority/Value:1' => 'Критический',
'Class:SLT/Attribute:priority/Value:1+' => 'Критический',
'Class:SLT/Attribute:priority/Value:2' => 'Высокий',
'Class:SLT/Attribute:priority/Value:2+' => 'Высокий',
'Class:SLT/Attribute:priority/Value:3' => 'Средний',
'Class:SLT/Attribute:priority/Value:3+' => 'Средний',
'Class:SLT/Attribute:priority/Value:4' => 'Низкий',
'Class:SLT/Attribute:priority/Value:4+' => 'Низкий',
'Class:SLT/Attribute:request_type' => 'Тип запроса',
'Class:SLT/Attribute:request_type+' => '',
'Class:SLT/Attribute:request_type/Value:incident' => 'Инцидент',
'Class:SLT/Attribute:request_type/Value:incident+' => 'Инцидент',
'Class:SLT/Attribute:request_type/Value:service_request' => 'Запрос на обслуживание',
'Class:SLT/Attribute:request_type/Value:service_request+' => 'Запрос на обслуживание',
'Class:SLT/Attribute:metric' => 'Метрика',
'Class:SLT/Attribute:metric+' => '',
'Class:SLT/Attribute:metric/Value:tto' => 'TTO',
'Class:SLT/Attribute:metric/Value:tto+' => 'Time-To-Own - время до назначения агента (принятия в работу)',
'Class:SLT/Attribute:metric/Value:ttr' => 'TTR',
'Class:SLT/Attribute:metric/Value:ttr+' => 'Time-To-Resolve - время до решения',
'Class:SLT/Attribute:value' => 'Значение',
'Class:SLT/Attribute:value+' => '',
'Class:SLT/Attribute:unit' => 'Единицы',
'Class:SLT/Attribute:unit+' => '',
'Class:SLT/Attribute:unit/Value:hours' => 'Часы',
'Class:SLT/Attribute:unit/Value:hours+' => 'Часы',
'Class:SLT/Attribute:unit/Value:minutes' => 'Минуты',
'Class:SLT/Attribute:unit/Value:minutes+' => 'Минуты',
));
//
// Class: lnkSLAToSLT
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkSLAToSLT' => 'Связь SLA/SLT',
'Class:lnkSLAToSLT+' => '',
'Class:lnkSLAToSLT/Attribute:sla_id' => 'SLA',
'Class:lnkSLAToSLT/Attribute:sla_id+' => '',
'Class:lnkSLAToSLT/Attribute:sla_name' => 'SLA',
'Class:lnkSLAToSLT/Attribute:sla_name+' => '',
'Class:lnkSLAToSLT/Attribute:slt_id' => 'SLT',
'Class:lnkSLAToSLT/Attribute:slt_id+' => '',
'Class:lnkSLAToSLT/Attribute:slt_name' => 'SLT',
'Class:lnkSLAToSLT/Attribute:slt_name+' => '',
));
//
// Class: lnkCustomerContractToService
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkCustomerContractToService' => 'Связь Договор с заказчиком/Услуга',
'Class:lnkCustomerContractToService+' => '',
'Class:lnkCustomerContractToService/Attribute:customercontract_id' => 'Договор с заказчиком',
'Class:lnkCustomerContractToService/Attribute:customercontract_id+' => '',
'Class:lnkCustomerContractToService/Attribute:customercontract_name' => 'Договор с заказчиком',
'Class:lnkCustomerContractToService/Attribute:customercontract_name+' => '',
'Class:lnkCustomerContractToService/Attribute:service_id' => 'Услуга',
'Class:lnkCustomerContractToService/Attribute:service_id+' => '',
'Class:lnkCustomerContractToService/Attribute:service_name' => 'Услуга',
'Class:lnkCustomerContractToService/Attribute:service_name+' => '',
'Class:lnkCustomerContractToService/Attribute:sla_id' => 'SLA',
'Class:lnkCustomerContractToService/Attribute:sla_id+' => '',
'Class:lnkCustomerContractToService/Attribute:sla_name' => 'SLA',
'Class:lnkCustomerContractToService/Attribute:sla_name+' => '',
));
//
// Class: lnkCustomerContractToProviderContract
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkCustomerContractToProviderContract' => 'Связь Договор с заказчиком/Договор с поставщиком',
'Class:lnkCustomerContractToProviderContract+' => '',
'Class:lnkCustomerContractToProviderContract/Attribute:customercontract_id' => 'Договор с заказчиком',
'Class:lnkCustomerContractToProviderContract/Attribute:customercontract_id+' => '',
'Class:lnkCustomerContractToProviderContract/Attribute:customercontract_name' => 'Договор с заказчиком',
'Class:lnkCustomerContractToProviderContract/Attribute:customercontract_name+' => '',
'Class:lnkCustomerContractToProviderContract/Attribute:providercontract_id' => 'Договор с поставщиком',
'Class:lnkCustomerContractToProviderContract/Attribute:providercontract_id+' => '',
'Class:lnkCustomerContractToProviderContract/Attribute:providercontract_name' => 'Договор с поставщиком',
'Class:lnkCustomerContractToProviderContract/Attribute:providercontract_name+' => '',
));
//
// Class: lnkCustomerContractToFunctionalCI
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkCustomerContractToFunctionalCI' => 'Связь Договор с заказчиком/Функциональная КЕ',
'Class:lnkCustomerContractToFunctionalCI+' => '',
'Class:lnkCustomerContractToFunctionalCI/Attribute:customercontract_id' => 'Договор с заказчиком',
'Class:lnkCustomerContractToFunctionalCI/Attribute:customercontract_id+' => '',
'Class:lnkCustomerContractToFunctionalCI/Attribute:customercontract_name' => 'Договор с заказчиком',
'Class:lnkCustomerContractToFunctionalCI/Attribute:customercontract_name+' => '',
'Class:lnkCustomerContractToFunctionalCI/Attribute:functionalci_id' => 'КЕ',
'Class:lnkCustomerContractToFunctionalCI/Attribute:functionalci_id+' => '',
'Class:lnkCustomerContractToFunctionalCI/Attribute:functionalci_name' => 'КЕ',
'Class:lnkCustomerContractToFunctionalCI/Attribute:functionalci_name+' => '',
));
//
// Class: DeliveryModel
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:DeliveryModel' => 'Модель предоставления услуг',
'Class:DeliveryModel+' => '',
'Class:DeliveryModel/Attribute:name' => 'Название',
'Class:DeliveryModel/Attribute:name+' => '',
'Class:DeliveryModel/Attribute:org_id' => 'Организация',
'Class:DeliveryModel/Attribute:org_id+' => '',
'Class:DeliveryModel/Attribute:organization_name' => 'Организация',
'Class:DeliveryModel/Attribute:organization_name+' => '',
'Class:DeliveryModel/Attribute:description' => 'Описание',
'Class:DeliveryModel/Attribute:description+' => '',
'Class:DeliveryModel/Attribute:contacts_list' => 'Контакты',
'Class:DeliveryModel/Attribute:contacts_list+' => 'Контакты (команды и персоны), которые участвуют в предоставлении услуг по этой модели',
'Class:DeliveryModel/Attribute:customers_list' => 'Заказчики',
'Class:DeliveryModel/Attribute:customers_list+' => 'Заказчики, которым предоставляются услуги по этой модели',
));
//
// Class: lnkDeliveryModelToContact
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkDeliveryModelToContact' => 'Связь Модель предоставления услуг/Контакт',
'Class:lnkDeliveryModelToContact+' => '',
'Class:lnkDeliveryModelToContact/Attribute:deliverymodel_id' => 'Модель предоставления услуг',
'Class:lnkDeliveryModelToContact/Attribute:deliverymodel_id+' => '',
'Class:lnkDeliveryModelToContact/Attribute:deliverymodel_name' => 'Модель предоставления услуг',
'Class:lnkDeliveryModelToContact/Attribute:deliverymodel_name+' => '',
'Class:lnkDeliveryModelToContact/Attribute:contact_id' => 'Контакт',
'Class:lnkDeliveryModelToContact/Attribute:contact_id+' => '',
'Class:lnkDeliveryModelToContact/Attribute:contact_name' => 'Контакт',
'Class:lnkDeliveryModelToContact/Attribute:contact_name+' => '',
'Class:lnkDeliveryModelToContact/Attribute:role_id' => 'Роль',
'Class:lnkDeliveryModelToContact/Attribute:role_id+' => '',
'Class:lnkDeliveryModelToContact/Attribute:role_name' => 'Роль',
'Class:lnkDeliveryModelToContact/Attribute:role_name+' => '',
));

View File

@@ -174,6 +174,7 @@
</fields>
<methods/>
<presentation>
<parent>Typology</parent>
<details>
<items>
<item id="name">

View File

@@ -2,20 +2,39 @@
/**
* Локализация интерфейса Combodo iTop подготовлена сообществом iTop по-русски http://community.itop-itsm.ru.
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @license http://opensource.org/licenses/AGPL-3.0
*
* @author Vladimir Kunin <v.b.kunin@gmail.com>
* @link http://community.itop-itsm.ru iTop Russian Community
* @link https://github.com/itop-itsm-ru/itop-rus
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*
* Инструкция по установке
*
* Процесс установки заключается в замене имеющихся локализационных файлов полученными и последующем запуске процедуры обновления iTop для перекомпиляции кода.
* 1. Скопируйте с заменой два полученных файла из "itop-rus/dictionaries" в "путь/до/вашего/itop/dictionaries".
* 2. Скопируйте с заменой полученные файлы "itop-rus/datamodels/2.x/название-модуля/ru.dict.название-модуля.php" в "путь/до/вашего/itop/datamodels/2.x/название-модуля".
* 3. Перейдите по адресу "http://адрес/вашего/itop/setup", при этом файл "путь/до/вашего/itop/conf/production/config-itop.php" должен быть доступен для записи.
* 4. На второй странице установщика выберите "Upgrade an existing iTop instance" и следуйте дальнейшим инструкциям установщика.
*
* Ответы на вопросы по установке и использованию переводов, а также на любые другие вопросы по iTop всегда можно получить на сайте сообщества iTop по-русски http://community.itop-itsm.ru.
*
*/
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Menu:ServiceManagement' => 'Управление услугами',
'Menu:ServiceManagement+' => 'Управление услугами',
'Menu:Service:Overview' => 'Обзор',
'Menu:Service:Overview+' => 'Управление услугами - Обзор',
'Menu:Service:Overview+' => '',
'UI-ServiceManagementMenu-ContractsBySrvLevel' => 'Договоры по уровню услуг',
'UI-ServiceManagementMenu-ContractsByStatus' => 'Договоры по статусу',
'UI-ServiceManagementMenu-ContractsEndingIn30Days' => 'Договоры, оканчивающиеся в течение 30-ти дней',
@@ -35,7 +54,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Menu:SLT' => 'SLT',
'Menu:SLT+' => 'Целевые показатели уровня услуг',
'Menu:DeliveryModel' => 'Модели предоставления услуг',
'Menu:DeliveryModel+' => 'Модели предоставления услуг (Delivery Models)',
'Menu:DeliveryModel+' => 'Модели предоставления услуг (Delivery models)',
'Menu:ServiceFamily' => 'Пакеты услуг',
'Menu:ServiceFamily+' => 'Пакеты услуг',
'Menu:Procedure' => 'Каталог процедур',
@@ -50,9 +69,9 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Organization/Attribute:deliverymodel_id' => 'Модель предоставления услуг',
'Class:Organization/Attribute:deliverymodel_id+' => 'Модель предоставления услуг (Delivery Model)',
'Class:Organization/Attribute:deliverymodel_name' => 'Модель предоставления услуг',
'Class:Organization/Attribute:deliverymodel_id' => 'Delivery model',
'Class:Organization/Attribute:deliverymodel_id+' => '',
'Class:Organization/Attribute:deliverymodel_name' => 'Delivery model name',
));
@@ -77,8 +96,8 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Contract/Attribute:name+' => '',
'Class:Contract/Attribute:org_id' => 'Заказчик',
'Class:Contract/Attribute:org_id+' => '',
'Class:Contract/Attribute:organization_name' => 'Заказчик',
'Class:Contract/Attribute:organization_name+' => '',
'Class:Contract/Attribute:organization_name' => 'Имя заказчика',
'Class:Contract/Attribute:organization_name+' => 'Common name',
'Class:Contract/Attribute:contacts_list' => 'Контакты',
'Class:Contract/Attribute:contacts_list+' => 'Связанные контакты',
'Class:Contract/Attribute:documents_list' => 'Документы',
@@ -99,25 +118,25 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Contract/Attribute:cost_currency/Value:euros+' => '',
'Class:Contract/Attribute:contracttype_id' => 'Тип договора',
'Class:Contract/Attribute:contracttype_id+' => '',
'Class:Contract/Attribute:contracttype_name' => 'Тип договора',
'Class:Contract/Attribute:contracttype_name' => 'Имя типа договора',
'Class:Contract/Attribute:contracttype_name+' => '',
'Class:Contract/Attribute:billing_frequency' => 'Периодичность платежей',
'Class:Contract/Attribute:billing_frequency' => 'Частота платежей',
'Class:Contract/Attribute:billing_frequency+' => '',
'Class:Contract/Attribute:cost_unit' => 'Единица стоимости',
'Class:Contract/Attribute:cost_unit+' => '',
'Class:Contract/Attribute:provider_id' => 'Поставщик',
'Class:Contract/Attribute:provider_id+' => '',
'Class:Contract/Attribute:provider_name' => 'Поставщик',
'Class:Contract/Attribute:provider_name+' => '',
'Class:Contract/Attribute:provider_name' => 'Имя поставщика',
'Class:Contract/Attribute:provider_name+' => 'Common name',
'Class:Contract/Attribute:status' => 'Статус',
'Class:Contract/Attribute:status+' => '',
'Class:Contract/Attribute:status/Value:implementation' => 'Внедрение',
'Class:Contract/Attribute:status/Value:implementation+' => 'Внедрение',
'Class:Contract/Attribute:status/Value:implementation+' => 'implementation',
'Class:Contract/Attribute:status/Value:obsolete' => 'Устаревшее',
'Class:Contract/Attribute:status/Value:obsolete+' => 'Устаревшее',
'Class:Contract/Attribute:status/Value:production' => 'Эксплуатация',
'Class:Contract/Attribute:status/Value:production+' => 'Эксплуатация',
'Class:Contract/Attribute:finalclass' => 'Тип',
'Class:Contract/Attribute:status/Value:obsolete+' => 'obsolete',
'Class:Contract/Attribute:status/Value:production' => 'Производство',
'Class:Contract/Attribute:status/Value:production+' => 'production',
'Class:Contract/Attribute:finalclass' => 'Тип договора',
'Class:Contract/Attribute:finalclass+' => '',
));
//
@@ -128,7 +147,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:CustomerContract' => 'Договор с заказчиком',
'Class:CustomerContract+' => '',
'Class:CustomerContract/Attribute:services_list' => 'Услуги',
'Class:CustomerContract/Attribute:services_list+' => 'Все услуги, предоставляемые по договору',
'Class:CustomerContract/Attribute:services_list+' => 'Связанные услуги',
));
//
@@ -139,14 +158,14 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:ProviderContract' => 'Договор с поставщиком',
'Class:ProviderContract+' => '',
'Class:ProviderContract/Attribute:functionalcis_list' => 'КЕ',
'Class:ProviderContract/Attribute:functionalcis_list+' => 'Конфигурационные единицы, охватываемые договором',
'Class:ProviderContract/Attribute:functionalcis_list+' => 'Связанные конфигурационные единицы',
'Class:ProviderContract/Attribute:sla' => 'SLA',
'Class:ProviderContract/Attribute:sla+' => 'Соглашение об уровне услуги (Service Level Agreement)',
'Class:ProviderContract/Attribute:coverage' => 'Время обслуживания',
'Class:ProviderContract/Attribute:coverage' => 'Время работы',
'Class:ProviderContract/Attribute:coverage+' => '',
'Class:ProviderContract/Attribute:contracttype_id' => 'Тип договора',
'Class:ProviderContract/Attribute:contracttype_id+' => '',
'Class:ProviderContract/Attribute:contracttype_name' => 'Тип договора',
'Class:ProviderContract/Attribute:contracttype_name' => 'Имя типа договора',
'Class:ProviderContract/Attribute:contracttype_name+' => '',
));
@@ -159,11 +178,11 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkContactToContract+' => '',
'Class:lnkContactToContract/Attribute:contract_id' => 'Договор',
'Class:lnkContactToContract/Attribute:contract_id+' => '',
'Class:lnkContactToContract/Attribute:contract_name' => 'Договор',
'Class:lnkContactToContract/Attribute:contract_name' => 'Имя договора',
'Class:lnkContactToContract/Attribute:contract_name+' => '',
'Class:lnkContactToContract/Attribute:contact_id' => 'Контакт',
'Class:lnkContactToContract/Attribute:contact_id+' => '',
'Class:lnkContactToContract/Attribute:contact_name' => 'Контакт',
'Class:lnkContactToContract/Attribute:contact_name' => 'Контактное лицо',
'Class:lnkContactToContract/Attribute:contact_name+' => '',
));
@@ -176,11 +195,11 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkContractToDocument+' => '',
'Class:lnkContractToDocument/Attribute:contract_id' => 'Договор',
'Class:lnkContractToDocument/Attribute:contract_id+' => '',
'Class:lnkContractToDocument/Attribute:contract_name' => 'Договор',
'Class:lnkContractToDocument/Attribute:contract_name' => 'Имя договора',
'Class:lnkContractToDocument/Attribute:contract_name+' => '',
'Class:lnkContractToDocument/Attribute:document_id' => 'Документ',
'Class:lnkContractToDocument/Attribute:document_id+' => '',
'Class:lnkContractToDocument/Attribute:document_name' => 'Документ',
'Class:lnkContractToDocument/Attribute:document_name' => 'Имя документа',
'Class:lnkContractToDocument/Attribute:document_name+' => '',
));
@@ -193,11 +212,11 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkFunctionalCIToProviderContract+' => '',
'Class:lnkFunctionalCIToProviderContract/Attribute:providercontract_id' => 'Договор с поставщиком',
'Class:lnkFunctionalCIToProviderContract/Attribute:providercontract_id+' => '',
'Class:lnkFunctionalCIToProviderContract/Attribute:providercontract_name' => 'Договор с поставщиком',
'Class:lnkFunctionalCIToProviderContract/Attribute:providercontract_name' => 'Имя договора поставщика',
'Class:lnkFunctionalCIToProviderContract/Attribute:providercontract_name+' => '',
'Class:lnkFunctionalCIToProviderContract/Attribute:functionalci_id' => 'КЕ',
'Class:lnkFunctionalCIToProviderContract/Attribute:functionalci_id+' => '',
'Class:lnkFunctionalCIToProviderContract/Attribute:functionalci_name' => 'КЕ',
'Class:lnkFunctionalCIToProviderContract/Attribute:functionalci_name' => 'Имя КЕ',
'Class:lnkFunctionalCIToProviderContract/Attribute:functionalci_name+' => '',
));
@@ -225,11 +244,11 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Service/Attribute:name+' => '',
'Class:Service/Attribute:org_id' => 'Поставщик',
'Class:Service/Attribute:org_id+' => '',
'Class:Service/Attribute:organization_name' => 'Поставщик',
'Class:Service/Attribute:organization_name' => 'Имя поставщика',
'Class:Service/Attribute:organization_name+' => '',
'Class:Service/Attribute:servicefamily_id' => 'Пакет услуг',
'Class:Service/Attribute:servicefamily_id+' => '',
'Class:Service/Attribute:servicefamily_name' => 'Пакет услуг',
'Class:Service/Attribute:servicefamily_name' => 'Имя пакета услуг',
'Class:Service/Attribute:servicefamily_name+' => '',
'Class:Service/Attribute:description' => 'Описание',
'Class:Service/Attribute:description+' => '',
@@ -240,17 +259,17 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Service/Attribute:status' => 'Статус',
'Class:Service/Attribute:status+' => '',
'Class:Service/Attribute:status/Value:implementation' => 'Внедрение',
'Class:Service/Attribute:status/Value:implementation+' => 'Внедрение',
'Class:Service/Attribute:status/Value:implementation+' => '',
'Class:Service/Attribute:status/Value:obsolete' => 'Устаревшее',
'Class:Service/Attribute:status/Value:obsolete+' => 'Устаревшее',
'Class:Service/Attribute:status/Value:production' => 'Эксплуатация',
'Class:Service/Attribute:status/Value:production+' => 'Эксплуатация',
'Class:Service/Attribute:status/Value:obsolete+' => '',
'Class:Service/Attribute:status/Value:production' => 'Производство',
'Class:Service/Attribute:status/Value:production+' => '',
'Class:Service/Attribute:customercontracts_list' => 'Договоры с заказчиками',
'Class:Service/Attribute:customercontracts_list+' => 'Договоры с заказчиками, по которым предоставляется услуга',
'Class:Service/Attribute:customercontracts_list+' => 'Договоры с заказчиками',
'Class:Service/Attribute:providercontracts_list' => 'Договоры с поставщиками',
'Class:Service/Attribute:providercontracts_list+' => 'Договоры с поставщиками, по которым поддерживается услуга',
'Class:Service/Attribute:providercontracts_list+' => 'Договоры с поставщиками',
'Class:Service/Attribute:functionalcis_list' => 'Зависимость от КЕ',
'Class:Service/Attribute:functionalcis_list+' => 'Конфигурационные единицы, которые используются для предоставления услуги',
'Class:Service/Attribute:functionalcis_list+' => 'Зависимость услуги от конфигурационных единиц',
'Class:Service/Attribute:servicesubcategories_list' => 'Подкатегории услуги',
'Class:Service/Attribute:servicesubcategories_list+' => 'Подкатегории услуги',
));
@@ -264,11 +283,11 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkDocumentToService+' => '',
'Class:lnkDocumentToService/Attribute:service_id' => 'Услуга',
'Class:lnkDocumentToService/Attribute:service_id+' => '',
'Class:lnkDocumentToService/Attribute:service_name' => 'Услуга',
'Class:lnkDocumentToService/Attribute:service_name' => 'Имя услуги',
'Class:lnkDocumentToService/Attribute:service_name+' => '',
'Class:lnkDocumentToService/Attribute:document_id' => 'Документ',
'Class:lnkDocumentToService/Attribute:document_id+' => '',
'Class:lnkDocumentToService/Attribute:document_name' => 'Документ',
'Class:lnkDocumentToService/Attribute:document_name' => 'Имя документа',
'Class:lnkDocumentToService/Attribute:document_name+' => '',
));
@@ -281,11 +300,11 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkContactToService+' => '',
'Class:lnkContactToService/Attribute:service_id' => 'Услуга',
'Class:lnkContactToService/Attribute:service_id+' => '',
'Class:lnkContactToService/Attribute:service_name' => 'Услуга',
'Class:lnkContactToService/Attribute:service_name' => 'Имя услуги',
'Class:lnkContactToService/Attribute:service_name+' => '',
'Class:lnkContactToService/Attribute:contact_id' => 'Контакт',
'Class:lnkContactToService/Attribute:contact_id+' => '',
'Class:lnkContactToService/Attribute:contact_name' => 'Контакт',
'Class:lnkContactToService/Attribute:contact_name' => 'Контактное лицо',
'Class:lnkContactToService/Attribute:contact_name+' => '',
));
@@ -307,19 +326,17 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:ServiceSubcategory/Attribute:request_type' => 'Тип запроса',
'Class:ServiceSubcategory/Attribute:request_type+' => '',
'Class:ServiceSubcategory/Attribute:request_type/Value:incident' => 'Инцидент',
'Class:ServiceSubcategory/Attribute:request_type/Value:incident+' => 'Инцидент',
'Class:ServiceSubcategory/Attribute:request_type/Value:incident+' => 'incident',
'Class:ServiceSubcategory/Attribute:request_type/Value:service_request' => 'Запрос на обслуживание',
'Class:ServiceSubcategory/Attribute:request_type/Value:service_request+' => 'Запрос на обслуживание',
'Class:ServiceSubcategory/Attribute:request_type/Value:service_request+' => 'service request',
'Class:ServiceSubcategory/Attribute:status' => 'Статус',
'Class:ServiceSubcategory/Attribute:status+' => '',
'Class:ServiceSubcategory/Attribute:status/Value:implementation' => 'Внедрение',
'Class:ServiceSubcategory/Attribute:status/Value:implementation+' => 'Внедрение',
'Class:ServiceSubcategory/Attribute:status/Value:implementation+' => 'implementation',
'Class:ServiceSubcategory/Attribute:status/Value:obsolete' => 'Устаревшее',
'Class:ServiceSubcategory/Attribute:status/Value:obsolete+' => 'Устаревшее',
'Class:ServiceSubcategory/Attribute:status/Value:production' => 'Эксплуатация',
'Class:ServiceSubcategory/Attribute:status/Value:production+' => 'Эксплуатация',
'Class:ServiceSubcategory/Attribute:service_provider' => 'Поставщик',
'Class:ServiceSubcategory/Attribute:service_org_id' => 'Поставщик',
'Class:ServiceSubcategory/Attribute:status/Value:obsolete+' => 'obsolete',
'Class:ServiceSubcategory/Attribute:status/Value:production' => 'Производство',
'Class:ServiceSubcategory/Attribute:status/Value:production+' => 'production',
));
//
@@ -335,12 +352,12 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:SLA/Attribute:description+' => '',
'Class:SLA/Attribute:org_id' => 'Поставщик',
'Class:SLA/Attribute:org_id+' => '',
'Class:SLA/Attribute:organization_name' => 'Поставщик',
'Class:SLA/Attribute:organization_name+' => '',
'Class:SLA/Attribute:organization_name' => 'Имя поставщика',
'Class:SLA/Attribute:organization_name+' => 'Common name',
'Class:SLA/Attribute:slts_list' => 'SLT',
'Class:SLA/Attribute:slts_list+' => 'Целевые показатели уровня услуги (Service Level Target)',
'Class:SLA/Attribute:slts_list+' => 'Целевой показатель уровня услуги (Service Level Target)',
'Class:SLA/Attribute:customercontracts_list' => 'Договоры с заказчиками',
'Class:SLA/Attribute:customercontracts_list+' => 'Договоры с заказчиками, в которых используется SLA',
'Class:SLA/Attribute:customercontracts_list+' => 'Договоры с заказчиками',
));
//
@@ -355,33 +372,33 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:SLT/Attribute:priority' => 'Приоритет',
'Class:SLT/Attribute:priority+' => '',
'Class:SLT/Attribute:priority/Value:1' => 'Критический',
'Class:SLT/Attribute:priority/Value:1+' => 'Критический',
'Class:SLT/Attribute:priority/Value:1+' => 'critical',
'Class:SLT/Attribute:priority/Value:2' => 'Высокий',
'Class:SLT/Attribute:priority/Value:2+' => 'Высокий',
'Class:SLT/Attribute:priority/Value:2+' => 'high',
'Class:SLT/Attribute:priority/Value:3' => 'Средний',
'Class:SLT/Attribute:priority/Value:3+' => 'Средний',
'Class:SLT/Attribute:priority/Value:3+' => 'medium',
'Class:SLT/Attribute:priority/Value:4' => 'Низкий',
'Class:SLT/Attribute:priority/Value:4+' => 'Низкий',
'Class:SLT/Attribute:priority/Value:4+' => 'low',
'Class:SLT/Attribute:request_type' => 'Тип запроса',
'Class:SLT/Attribute:request_type+' => '',
'Class:SLT/Attribute:request_type/Value:incident' => 'Инцидент',
'Class:SLT/Attribute:request_type/Value:incident+' => 'Инцидент',
'Class:SLT/Attribute:request_type/Value:service_request' => 'Запрос на обслуживание',
'Class:SLT/Attribute:request_type/Value:service_request+' => 'Запрос на обслуживание',
'Class:SLT/Attribute:request_type/Value:incident+' => 'incident',
'Class:SLT/Attribute:request_type/Value:service_request' => 'service request',
'Class:SLT/Attribute:request_type/Value:service_request+' => 'service request',
'Class:SLT/Attribute:metric' => 'Метрика',
'Class:SLT/Attribute:metric+' => '',
'Class:SLT/Attribute:metric/Value:tto' => 'TTO',
'Class:SLT/Attribute:metric/Value:tto+' => 'Time-To-Own - время до назначения агента (принятия в работу)',
'Class:SLT/Attribute:metric/Value:tto+' => 'TTO',
'Class:SLT/Attribute:metric/Value:ttr' => 'TTR',
'Class:SLT/Attribute:metric/Value:ttr+' => 'Time-To-Resolve - время до решения',
'Class:SLT/Attribute:metric/Value:ttr+' => 'TTR',
'Class:SLT/Attribute:value' => 'Значение',
'Class:SLT/Attribute:value+' => '',
'Class:SLT/Attribute:unit' => 'Единицы',
'Class:SLT/Attribute:unit+' => '',
'Class:SLT/Attribute:unit/Value:hours' => 'Часы',
'Class:SLT/Attribute:unit/Value:hours+' => 'Часы',
'Class:SLT/Attribute:unit/Value:hours+' => 'часов',
'Class:SLT/Attribute:unit/Value:minutes' => 'Минуты',
'Class:SLT/Attribute:unit/Value:minutes+' => 'Минуты',
'Class:SLT/Attribute:unit/Value:minutes+' => 'минут',
));
//
@@ -393,11 +410,11 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkSLAToSLT+' => '',
'Class:lnkSLAToSLT/Attribute:sla_id' => 'SLA',
'Class:lnkSLAToSLT/Attribute:sla_id+' => '',
'Class:lnkSLAToSLT/Attribute:sla_name' => 'SLA',
'Class:lnkSLAToSLT/Attribute:sla_name' => 'Название SLA',
'Class:lnkSLAToSLT/Attribute:sla_name+' => '',
'Class:lnkSLAToSLT/Attribute:slt_id' => 'SLT',
'Class:lnkSLAToSLT/Attribute:slt_id+' => '',
'Class:lnkSLAToSLT/Attribute:slt_name' => 'SLT',
'Class:lnkSLAToSLT/Attribute:slt_name' => 'Название SLT',
'Class:lnkSLAToSLT/Attribute:slt_name+' => '',
));
@@ -410,15 +427,15 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkCustomerContractToService+' => '',
'Class:lnkCustomerContractToService/Attribute:customercontract_id' => 'Договор с заказчиком',
'Class:lnkCustomerContractToService/Attribute:customercontract_id+' => '',
'Class:lnkCustomerContractToService/Attribute:customercontract_name' => 'Договор с заказчиком',
'Class:lnkCustomerContractToService/Attribute:customercontract_name' => 'Контактное лицо клиента',
'Class:lnkCustomerContractToService/Attribute:customercontract_name+' => '',
'Class:lnkCustomerContractToService/Attribute:service_id' => 'Услуга',
'Class:lnkCustomerContractToService/Attribute:service_id+' => '',
'Class:lnkCustomerContractToService/Attribute:service_name' => 'Услуга',
'Class:lnkCustomerContractToService/Attribute:service_name' => 'Имя услуги',
'Class:lnkCustomerContractToService/Attribute:service_name+' => '',
'Class:lnkCustomerContractToService/Attribute:sla_id' => 'SLA',
'Class:lnkCustomerContractToService/Attribute:sla_id+' => '',
'Class:lnkCustomerContractToService/Attribute:sla_name' => 'SLA',
'Class:lnkCustomerContractToService/Attribute:sla_name' => 'Название SLA',
'Class:lnkCustomerContractToService/Attribute:sla_name+' => '',
));
@@ -431,11 +448,11 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkProviderContractToService+' => '',
'Class:lnkProviderContractToService/Attribute:service_id' => 'Услуга',
'Class:lnkProviderContractToService/Attribute:service_id+' => '',
'Class:lnkProviderContractToService/Attribute:service_name' => 'Услуга',
'Class:lnkProviderContractToService/Attribute:service_name' => 'Имя услуги',
'Class:lnkProviderContractToService/Attribute:service_name+' => '',
'Class:lnkProviderContractToService/Attribute:providercontract_id' => 'Договор с поставщиком',
'Class:lnkProviderContractToService/Attribute:providercontract_id+' => '',
'Class:lnkProviderContractToService/Attribute:providercontract_name' => 'Договор с поставщиком',
'Class:lnkProviderContractToService/Attribute:providercontract_name' => 'Имя договора поставщика',
'Class:lnkProviderContractToService/Attribute:providercontract_name+' => '',
));
@@ -448,11 +465,11 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkFunctionalCIToService+' => '',
'Class:lnkFunctionalCIToService/Attribute:service_id' => 'Услуга',
'Class:lnkFunctionalCIToService/Attribute:service_id+' => '',
'Class:lnkFunctionalCIToService/Attribute:service_name' => 'Услуга',
'Class:lnkFunctionalCIToService/Attribute:service_name' => 'Имя услуги',
'Class:lnkFunctionalCIToService/Attribute:service_name+' => '',
'Class:lnkFunctionalCIToService/Attribute:functionalci_id' => 'КЕ',
'Class:lnkFunctionalCIToService/Attribute:functionalci_id+' => '',
'Class:lnkFunctionalCIToService/Attribute:functionalci_name' => 'КЕ',
'Class:lnkFunctionalCIToService/Attribute:functionalci_name' => 'Имя КЕ',
'Class:lnkFunctionalCIToService/Attribute:functionalci_name+' => '',
));
@@ -467,14 +484,14 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:DeliveryModel/Attribute:name+' => '',
'Class:DeliveryModel/Attribute:org_id' => 'Организация',
'Class:DeliveryModel/Attribute:org_id+' => '',
'Class:DeliveryModel/Attribute:organization_name' => 'Организация',
'Class:DeliveryModel/Attribute:organization_name+' => '',
'Class:DeliveryModel/Attribute:organization_name' => 'Название организации',
'Class:DeliveryModel/Attribute:organization_name+' => 'Common name',
'Class:DeliveryModel/Attribute:description' => 'Описание',
'Class:DeliveryModel/Attribute:description+' => '',
'Class:DeliveryModel/Attribute:contacts_list' => 'Контакты',
'Class:DeliveryModel/Attribute:contacts_list+' => 'Контакты (команды и персоны), которые участвуют в предоставлении услуг по этой модели',
'Class:DeliveryModel/Attribute:contacts_list+' => 'Связанные контакты',
'Class:DeliveryModel/Attribute:customers_list' => 'Заказчики',
'Class:DeliveryModel/Attribute:customers_list+' => 'Заказчики, которым предоставляются услуги по этой модели',
'Class:DeliveryModel/Attribute:customers_list+' => 'Связанные заказчик',
));
//
@@ -486,14 +503,17 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:lnkDeliveryModelToContact+' => '',
'Class:lnkDeliveryModelToContact/Attribute:deliverymodel_id' => 'Модель предоставления услуг',
'Class:lnkDeliveryModelToContact/Attribute:deliverymodel_id+' => '',
'Class:lnkDeliveryModelToContact/Attribute:deliverymodel_name' => 'Модель предоставления услуг',
'Class:lnkDeliveryModelToContact/Attribute:deliverymodel_name' => 'Название модели предоставления услуг',
'Class:lnkDeliveryModelToContact/Attribute:deliverymodel_name+' => '',
'Class:lnkDeliveryModelToContact/Attribute:contact_id' => 'Контакт',
'Class:lnkDeliveryModelToContact/Attribute:contact_id+' => '',
'Class:lnkDeliveryModelToContact/Attribute:contact_name' => 'Контакт',
'Class:lnkDeliveryModelToContact/Attribute:contact_name' => 'Контактное лицо',
'Class:lnkDeliveryModelToContact/Attribute:contact_name+' => '',
'Class:lnkDeliveryModelToContact/Attribute:role_id' => 'Роль',
'Class:lnkDeliveryModelToContact/Attribute:role_id+' => '',
'Class:lnkDeliveryModelToContact/Attribute:role_name' => 'Роль',
'Class:lnkDeliveryModelToContact/Attribute:role_name' => 'Должность',
'Class:lnkDeliveryModelToContact/Attribute:role_name+' => '',
));
));
?>

View File

@@ -698,7 +698,7 @@
<code><![CDATA[ public function UpdateParentTicketLog()
{
$oLog = $this->Get('log');
$sLog = $oLog->GetModifiedEntry('html');
$sLog = $oLog->GetModifiedEntry();
if ($sLog != '')
{
$oTicket = MetaModel::GetObject('Ticket', $this->Get('ticket_id'), false);
@@ -998,7 +998,7 @@
<default>fa fa-user fa-2x</default>
</decoration_class>
<form>
<!-- Optionnal tag to list the fields. If empty only fields from <twig> tag will be displayed, if ommited fields from zlist details will. -->
<!-- Optionnal tag to list the fields -->
<fields />
<!-- Optionnal tag to specify the form layout. Fields that are not positionned in the layout will be placed at the end of the form -->
<twig>
@@ -1052,7 +1052,7 @@
<!-- Description text from attribute of above class [from the OQL] -->
<tooltip_att>description</tooltip_att>
<!-- Title of the level, will be display in lists and others browse modes -->
<title>Class:Service</title>
<title>Service</title>
<!-- Optional tag to add attributes to the table by their code, can be specified for each level -->
<!-- <fields /> -->
<!-- Can be empty on intermediate levels, default is drilldown -->
@@ -1066,7 +1066,7 @@
<parent_att>service_id</parent_att>
<name_att/>
<tooltip_att>description</tooltip_att>
<title>Class:ServiceSubcategory</title>
<title>Sous-Service</title>
<actions>
<action id="view" xsi:type="view"/>
<action id="create_from_this" xsi:type="create_from_this">
@@ -1130,9 +1130,9 @@
</fields>
<!-- Optional tag to add attributes to the table by their code -->
<grouping>
<!-- Mandatory -->
<!-- Optionnal -->
<tabs>
<!-- Mandatory. Grouping by tabs -->
<!-- Optionnal. Grouping by tabs -->
<!--<attribute>operational_status</attribute>-->
<!-- attribute xor groups tag -->
<groups>
@@ -1145,7 +1145,7 @@
<group id="resolved">
<rank>2</rank>
<title>Brick:Portal:OngoingRequests:Tab:Resolved</title>
<condition><![CDATA[SELECT Ticket AS T WHERE operational_status = 'resolved']]></condition>
<condition><![CDATA[SELECT Ticket AS T WHERE org_id = :current_contact->org_id AND operational_status = 'resolved']]></condition>
</group>
</groups>
</tabs>
@@ -1169,7 +1169,7 @@
<decoration_class>
<default>fc fc-closed-request fc-2x</default>
</decoration_class>
<oql><![CDATA[SELECT Ticket WHERE org_id = :current_contact->org_id AND caller_id = :current_contact_id AND operational_status = 'closed']]></oql>
<oql><![CDATA[SELECT UserRequest WHERE org_id = :current_contact->org_id AND caller_id = :current_contact_id AND status = 'closed']]></oql>
<!-- Can be either a class tag with the class name or an oql tag with the query -->
<!-- <class>Ticket</class> -->
<fields>
@@ -1181,18 +1181,6 @@
<field id="priority"/>
<field id="caller_id"/>
</fields>
<grouping>
<tabs>
<groups>
<group id="all">
<rank>1</rank>
<title>Brick:Portal:ClosedRequests:Title</title>
<condition><![CDATA[SELECT Ticket]]></condition>
</group>
</groups>
</tabs>
<!-- Implicit grouping on y axis by finalclass -->
</grouping>
<data_loading>auto</data_loading>
</brick>
</bricks>
@@ -1321,21 +1309,6 @@
<mode id="view"/>
</modes>
</form>
<form id="ticket-apply-stimulus">
<class>Ticket</class>
<fields />
<twig>
<div>
<div class="form_field" data-field-id="team_id" data-field-flags="read_only">
</div>
<div class="form_field" data-field-id="agent_id" data-field-flags="read_only">
</div>
</div>
</twig>
<modes>
<mode id="apply_stimulus"/>
</modes>
</form>
<form id="service-view">
<class>Service</class>
<fields></fields>
@@ -1386,13 +1359,6 @@
</scope>
</scopes>
</class>
<class id="Location">
<scopes>
<scope id="all">
<oql_view><![CDATA[SELECT Location WHERE org_id = :current_contact->org_id]]></oql_view>
</scope>
</scopes>
</class>
<class id="Contact">
<scopes>
<scope id="all">
@@ -1425,7 +1391,6 @@
<scopes>
<scope id="all">
<oql_view><![CDATA[SELECT ServiceFamily AS sf JOIN Service AS s ON s.servicefamily_id = sf.id JOIN lnkCustomerContractToService AS l1 ON l1.service_id=s.id JOIN CustomerContract AS cc ON l1.customercontract_id=cc.id WHERE cc.org_id = :current_contact->org_id]]></oql_view>
<ignore_silos>true</ignore_silos>
</scope>
</scopes>
</class>
@@ -1433,7 +1398,6 @@
<scopes>
<scope id="all">
<oql_view><![CDATA[SELECT Service AS s JOIN lnkCustomerContractToService AS l1 ON l1.service_id=s.id JOIN CustomerContract AS cc ON l1.customercontract_id=cc.id WHERE cc.org_id = :current_contact->org_id AND s.status != 'obsolete']]></oql_view>
<ignore_silos>true</ignore_silos>
</scope>
</scopes>
</class>
@@ -1441,7 +1405,6 @@
<scopes>
<scope id="all">
<oql_view><![CDATA[SELECT ServiceSubcategory AS ssc JOIN Service AS s ON ssc.service_id=s.id JOIN lnkCustomerContractToService AS l1 ON l1.service_id=s.id JOIN CustomerContract AS cc ON l1.customercontract_id=cc.id WHERE cc.org_id = :current_contact->org_id AND ssc.status != 'obsolete']]></oql_view>
<ignore_silos>true</ignore_silos>
</scope>
</scopes>
</class>

Some files were not shown because too many files have changed in this diff Show More