mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 23:44:11 +01:00
Compare commits
184 Commits
support/de
...
2.4.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab6cf18445 | ||
|
|
a0171ac9cf | ||
|
|
4b4bb6aa0b | ||
|
|
ff8397edf6 | ||
|
|
d46dc519e1 | ||
|
|
fe7eb22d32 | ||
|
|
bafb6ab212 | ||
|
|
6c0e986563 | ||
|
|
cf06f3e0d5 | ||
|
|
fe887f01c0 | ||
|
|
9109138127 | ||
|
|
51b19c03b1 | ||
|
|
8cb584abdd | ||
|
|
3480d478b0 | ||
|
|
3a34417a7d | ||
|
|
6ca3ca108b | ||
|
|
037036ce6a | ||
|
|
9d2dab5eba | ||
|
|
3169b39952 | ||
|
|
ba33b01d84 | ||
|
|
7db69ed158 | ||
|
|
a6f6d536e0 | ||
|
|
880faf2021 | ||
|
|
f96902c03e | ||
|
|
6e810322f7 | ||
|
|
dd9984be7f | ||
|
|
98f3f88ea2 | ||
|
|
8be0c36859 | ||
|
|
8c5a65d836 | ||
|
|
db47973063 | ||
|
|
028e815bfa | ||
|
|
caf07affa6 | ||
|
|
bdef9e59de | ||
|
|
4bf001d108 | ||
|
|
a095208e53 | ||
|
|
2429ec4eec | ||
|
|
55655e3fca | ||
|
|
7e98b04ed3 | ||
|
|
59c6c0250d | ||
|
|
18a5afb8a6 | ||
|
|
4b6258dfa1 | ||
|
|
44b9f23117 | ||
|
|
2ddefcd2fc | ||
|
|
39b15fec50 | ||
|
|
c180dd9863 | ||
|
|
1172130d7c | ||
|
|
8172e14345 | ||
|
|
6e4836f5e0 | ||
|
|
4ee6e6f915 | ||
|
|
e5b318b94f | ||
|
|
c081b89f03 | ||
|
|
f237a98c1d | ||
|
|
fd2a41aee6 | ||
|
|
25b1a0d8af | ||
|
|
985b366cc7 | ||
|
|
d1e2bc9b2b | ||
|
|
757b3d1cc3 | ||
|
|
8c0bbadbfe | ||
|
|
cbd3d2c165 | ||
|
|
b286bd48c7 | ||
|
|
c4efbe2891 | ||
|
|
58506441cf | ||
|
|
d575ee50ee | ||
|
|
997fa3a856 | ||
|
|
70abd8027e | ||
|
|
4c6e6ffc9c | ||
|
|
b268df7bb4 | ||
|
|
7aaa35f88e | ||
|
|
4bb91b819c | ||
|
|
656cae3e66 | ||
|
|
292735b4b2 | ||
|
|
dcc4061261 | ||
|
|
ff7ac731df | ||
|
|
c784afdb06 | ||
|
|
5e60e8d725 | ||
|
|
564bf04647 | ||
|
|
17d18eb75f | ||
|
|
a9a6460747 | ||
|
|
1fa1a053e4 | ||
|
|
01e151632f | ||
|
|
c17d0b1027 | ||
|
|
517d16e3d9 | ||
|
|
696a5d1a48 | ||
|
|
96288db97b | ||
|
|
e6072cd8b6 | ||
|
|
db8bb7d94a | ||
|
|
1b2dbf751c | ||
|
|
b6805af20e | ||
|
|
4cc6290c88 | ||
|
|
c79d17516d | ||
|
|
a2154d6418 | ||
|
|
f820d3bd81 | ||
|
|
0a914f527a | ||
|
|
a8c749a46a | ||
|
|
e58c8afeab | ||
|
|
005b0eab1d | ||
|
|
55b34b5d11 | ||
|
|
7b4f00ee45 | ||
|
|
cc99cec250 | ||
|
|
105dc46f46 | ||
|
|
770fbe157c | ||
|
|
21d44c664f | ||
|
|
b318cbe211 | ||
|
|
7106501812 | ||
|
|
567dd39270 | ||
|
|
b292621f82 | ||
|
|
46f0b48add | ||
|
|
9a5f16bd3e | ||
|
|
6224ec7a37 | ||
|
|
c460edcd5e | ||
|
|
b839b42cd4 | ||
|
|
fabc8b91d7 | ||
|
|
4c38cd570c | ||
|
|
c4fd15ae90 | ||
|
|
bbca491118 | ||
|
|
0d04bd8b0e | ||
|
|
3bcb3a2154 | ||
|
|
aa863c40d3 | ||
|
|
5d7ad9f6dd | ||
|
|
72cb41dd7e | ||
|
|
6ef39c9f5b | ||
|
|
614b948c82 | ||
|
|
7c0715ad59 | ||
|
|
31819497ae | ||
|
|
c86e2c6c79 | ||
|
|
1d54b66de9 | ||
|
|
f932765e19 | ||
|
|
11b4085566 | ||
|
|
12afcd7cce | ||
|
|
666c95a656 | ||
|
|
fde9c28263 | ||
|
|
52c3ff0406 | ||
|
|
9f4d07aaa5 | ||
|
|
70561d6331 | ||
|
|
ae8311e224 | ||
|
|
e09fa0ffc1 | ||
|
|
5b6a20048f | ||
|
|
d86c211b73 | ||
|
|
8499babcb3 | ||
|
|
2d44cbbb60 | ||
|
|
3d89ef9076 | ||
|
|
e896f8af3d | ||
|
|
23268e8969 | ||
|
|
421e12debd | ||
|
|
389848cef4 | ||
|
|
7da4423346 | ||
|
|
2a770b9dc4 | ||
|
|
8df12e64f2 | ||
|
|
341261c14e | ||
|
|
bfc7c73e18 | ||
|
|
9a6c4ba7bb | ||
|
|
dc47c34981 | ||
|
|
3ac5131a19 | ||
|
|
134a9aa684 | ||
|
|
a98c0d32ae | ||
|
|
38af2b85c4 | ||
|
|
c9c84735c4 | ||
|
|
646972838a | ||
|
|
ce92241593 | ||
|
|
715eeff627 | ||
|
|
651de821df | ||
|
|
2233ea5f54 | ||
|
|
39e6915e05 | ||
|
|
6279f4ac70 | ||
|
|
badf10e74e | ||
|
|
2e9cd6a342 | ||
|
|
cef70ee9a2 | ||
|
|
37e15706b2 | ||
|
|
4b210273d2 | ||
|
|
951e8e03b0 | ||
|
|
c016ca364d | ||
|
|
4611442665 | ||
|
|
c7e7976607 | ||
|
|
0ca9fac04b | ||
|
|
7edc79f398 | ||
|
|
c110206264 | ||
|
|
b3ad2030cb | ||
|
|
0938ba939c | ||
|
|
bca393def3 | ||
|
|
796ac55ff4 | ||
|
|
66ae89e91d | ||
|
|
361cca465a | ||
|
|
7462d66643 | ||
|
|
a177b9b1d4 |
122
.gitignore
vendored
Normal file
122
.gitignore
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
|
||||
/toolkit/
|
||||
/conf/*
|
||||
/env-*/*
|
||||
|
||||
# composer reserver directory, from sources, populate/update using "composer install"
|
||||
vendor/*
|
||||
test/vendor/*
|
||||
|
||||
# all datas but listing prevention
|
||||
data/*
|
||||
!data/.htaccess
|
||||
!data/index.php
|
||||
!data/web.config
|
||||
|
||||
# iTop extensions
|
||||
extensions/*
|
||||
!extensions/readme.txt
|
||||
|
||||
# all logs but listing prevention
|
||||
log/*
|
||||
!log/.htaccess
|
||||
!log/index.php
|
||||
!log/web.config
|
||||
|
||||
|
||||
# Jetbrains
|
||||
.idea/**
|
||||
!.idea/encodings.xml
|
||||
!.idea/codeStyles
|
||||
!.idea/codeStyles/*
|
||||
!.idea/inspectionProfiles
|
||||
!.idea/inspectionProfiles/*
|
||||
|
||||
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
### Eclipse template
|
||||
|
||||
.metadata
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.settings/
|
||||
.loadpath
|
||||
.recommenders
|
||||
.project
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# PyDev specific (Python IDE for Eclipse)
|
||||
*.pydevproject
|
||||
|
||||
# CDT-specific (C/C++ Development Tooling)
|
||||
.cproject
|
||||
|
||||
# CDT- autotools
|
||||
.autotools
|
||||
|
||||
# Java annotation processor (APT)
|
||||
.factorypath
|
||||
|
||||
# PDT-specific (PHP Development Tools)
|
||||
.buildpath
|
||||
|
||||
# sbteclipse plugin
|
||||
.target
|
||||
|
||||
# Tern plugin
|
||||
.tern-project
|
||||
|
||||
# TeXlipse plugin
|
||||
.texlipse
|
||||
|
||||
# STS (Spring Tool Suite)
|
||||
.springBeans
|
||||
|
||||
# Code Recommenders
|
||||
.recommenders/
|
||||
|
||||
# Annotation Processing
|
||||
.apt_generated/
|
||||
|
||||
# Scala IDE specific (Scala & Java development for Eclipse)
|
||||
.cache-main
|
||||
.scala_dependencies
|
||||
.worksheet
|
||||
@@ -118,8 +118,7 @@ class ApplicationContext
|
||||
$oSearchFilter = new DBObjectSearch('Organization');
|
||||
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
|
||||
$oSet = new CMDBObjectSet($oSearchFilter);
|
||||
$iCount = $oSet->Count();
|
||||
if ($iCount == 1)
|
||||
if ($oSet->Count(2) == 1)
|
||||
{
|
||||
// Only one possible value for org_id, set it in the context
|
||||
$oOrg = $oSet->Fetch();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -755,33 +755,65 @@ EOF
|
||||
|
||||
public static function GetDashletCreationForm($sOQL = null)
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContextMenuId = $oAppContext->GetCurrentValue('menu', null);
|
||||
|
||||
$oForm = new DesignerForm();
|
||||
|
||||
// Get the list of all 'dashboard' menus in which we can insert a dashlet
|
||||
$aAllMenus = ApplicationMenu::ReflectionMenuNodes();
|
||||
$sRootMenuId = ApplicationMenu::GetRootMenuId($sContextMenuId);
|
||||
$aAllowedDashboards = array();
|
||||
foreach($aAllMenus as $idx => $aMenu)
|
||||
$sDefaultDashboard = null;
|
||||
|
||||
// Store the parent menus for acces check
|
||||
$aParentMenus = array();
|
||||
foreach($aAllMenus as $idx => $aMenu)
|
||||
{
|
||||
/** @var MenuNode $oMenu */
|
||||
$oMenu = $aMenu['node'];
|
||||
if (count(ApplicationMenu::GetChildren($oMenu->GetIndex())) > 0)
|
||||
{
|
||||
$aParentMenus[$oMenu->GetMenuId()] = $aMenu;
|
||||
}
|
||||
}
|
||||
|
||||
foreach($aAllMenus as $idx => $aMenu)
|
||||
{
|
||||
$oMenu = $aMenu['node'];
|
||||
$sParentId = $aMenu['parent'];
|
||||
if ($oMenu instanceof DashboardMenuNode)
|
||||
{
|
||||
$sMenuLabel = $oMenu->GetTitle();
|
||||
$sParentLabel = Dict::S('Menu:'.$sParentId);
|
||||
if ($sParentLabel != $sMenuLabel)
|
||||
{
|
||||
$aAllowedDashboards[$oMenu->GetMenuId()] = $sParentLabel.' - '.$sMenuLabel;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAllowedDashboards[$oMenu->GetMenuId()] = $sMenuLabel;
|
||||
}
|
||||
}
|
||||
if ($oMenu instanceof DashboardMenuNode)
|
||||
{
|
||||
// Get the root parent for access check
|
||||
$sParentId = $aMenu['parent'];
|
||||
$aParentMenu = $aParentMenus[$sParentId];
|
||||
while (isset($aParentMenus[$aParentMenu['parent']]))
|
||||
{
|
||||
// grand parent exists
|
||||
$sParentId = $aParentMenu['parent'];
|
||||
$aParentMenu = $aParentMenus[$sParentId];
|
||||
}
|
||||
$oParentMenu = $aParentMenu['node'];
|
||||
if ($oMenu->IsEnabled() && $oParentMenu->IsEnabled())
|
||||
{
|
||||
$sMenuLabel = $oMenu->GetTitle();
|
||||
$sParentLabel = Dict::S('Menu:'.$sParentId);
|
||||
if ($sParentLabel != $sMenuLabel)
|
||||
{
|
||||
$aAllowedDashboards[$oMenu->GetMenuId()] = $sParentLabel.' - '.$sMenuLabel;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAllowedDashboards[$oMenu->GetMenuId()] = $sMenuLabel;
|
||||
}
|
||||
if (empty($sDefaultDashboard) && ($sRootMenuId == ApplicationMenu::GetRootMenuId($oMenu->GetMenuId())))
|
||||
{
|
||||
$sDefaultDashboard = $oMenu->GetMenuId();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
asort($aAllowedDashboards);
|
||||
|
||||
$aKeys = array_keys($aAllowedDashboards); // Select the first one by default
|
||||
$sDefaultDashboard = $aKeys[0];
|
||||
$oField = new DesignerComboField('menu_id', Dict::S('UI:DashletCreation:Dashboard'), $sDefaultDashboard);
|
||||
$oField->SetAllowedValues($aAllowedDashboards);
|
||||
$oField->SetMandatory(true);
|
||||
@@ -842,7 +874,7 @@ EOF
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#dashlet_creation_dlg').dialog({
|
||||
width: 400,
|
||||
width: 600,
|
||||
modal: true,
|
||||
title: '$sDialogTitle',
|
||||
buttons: [
|
||||
|
||||
@@ -661,7 +661,7 @@ class DisplayBlock
|
||||
case 'links':
|
||||
//$bDashboardMode = isset($aExtraParams['dashboard']) ? ($aExtraParams['dashboard'] == 'true') : false;
|
||||
//$bSelectMode = isset($aExtraParams['select']) ? ($aExtraParams['select'] == 'true') : false;
|
||||
if ( ($this->m_oSet->Count()> 0) && (UserRights::IsActionAllowed($this->m_oSet->GetClass(), UR_ACTION_READ, $this->m_oSet) == UR_ALLOWED_YES) )
|
||||
if ( ($this->m_oSet->Count(1)> 0) && (UserRights::IsActionAllowed($this->m_oSet->GetClass(), UR_ACTION_READ, $this->m_oSet) == UR_ALLOWED_YES) )
|
||||
{
|
||||
//$sLinkage = isset($aExtraParams['linkage']) ? $aExtraParams['linkage'] : '';
|
||||
$sHtml .= cmdbAbstractObject::GetDisplaySet($oPage, $this->m_oSet, $aExtraParams);
|
||||
@@ -774,21 +774,38 @@ class DisplayBlock
|
||||
{
|
||||
$aStates = explode(',', $sStatesList);
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sStateAttrCode);
|
||||
|
||||
// Generate one count + group by query [#1330]
|
||||
$sClassAlias = $this->m_oFilter->GetClassAlias();
|
||||
$oGroupByExpr = Expression::FromOQL($sClassAlias.'.'.$sStateAttrCode);
|
||||
$aGroupBy = array('group1' => $oGroupByExpr);
|
||||
$sCountGroupByQuery = $this->m_oFilter->MakeGroupByQuery(array(), $aGroupBy, false);
|
||||
$aCountGroupByResults = CMDBSource::QueryToArray($sCountGroupByQuery);
|
||||
$aCountsQueryResults = array();
|
||||
foreach ($aCountGroupByResults as $aCountGroupBySingleResult)
|
||||
{
|
||||
$aCountsQueryResults[$aCountGroupBySingleResult[0]] = $aCountGroupBySingleResult[1];
|
||||
}
|
||||
|
||||
foreach($aStates as $sStateValue)
|
||||
{
|
||||
$oFilter = $this->m_oFilter->DeepClone();
|
||||
$oFilter->AddCondition($sStateAttrCode, $sStateValue, '=');
|
||||
$oSet = new DBObjectSet($oFilter);
|
||||
$oSet->SetShowObsoleteData($this->m_bShowObsoleteData);
|
||||
$aCounts[$sStateValue] = $oSet->Count();
|
||||
$aStateLabels[$sStateValue] = htmlentities($oAttDef->GetValueLabel($sStateValue), ENT_QUOTES, 'UTF-8');
|
||||
|
||||
$aCounts[$sStateValue] = (array_key_exists($sStateValue, $aCountsQueryResults))
|
||||
? $aCountsQueryResults[$sStateValue]
|
||||
: 0;
|
||||
|
||||
if ($aCounts[$sStateValue] == 0)
|
||||
{
|
||||
$aCounts[$sStateValue] = '-';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($oFilter->serialize());
|
||||
$oSingleGroupByValueFilter = $this->m_oFilter->DeepClone();
|
||||
$oSingleGroupByValueFilter->AddCondition($sStateAttrCode, $sStateValue, '=');
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot()
|
||||
.'pages/UI.php?operation=search&'.$oAppContext->GetForLink()
|
||||
.'&filter='.urlencode($oSingleGroupByValueFilter->serialize());
|
||||
$aCounts[$sStateValue] = "<a href=\"$sHyperlink\">{$aCounts[$sStateValue]}</a>";
|
||||
}
|
||||
}
|
||||
@@ -1567,7 +1584,7 @@ class MenuBlock extends DisplayBlock
|
||||
// Do not perform time consuming computations if there are too may objects in the list
|
||||
$iLimit = MetaModel::GetConfig()->Get('complex_actions_limit');
|
||||
|
||||
if ((count($aStates) > 0) && (($iLimit == 0) || ($oSet->Count() < $iLimit)))
|
||||
if ((count($aStates) > 0) && (($iLimit == 0) || ($oSet->Count($iLimit + 1) < $iLimit)))
|
||||
{
|
||||
// Life cycle actions may be available... if all objects are in the same state
|
||||
//
|
||||
|
||||
@@ -360,6 +360,7 @@ EOF
|
||||
<<<EOF
|
||||
$('#$sDialogId').dialog({
|
||||
height: 'auto',
|
||||
maxHeight: $(window).height() - 8,
|
||||
width: $iDialogWidth,
|
||||
modal: true,
|
||||
autoOpen: $sAutoOpen,
|
||||
|
||||
@@ -331,31 +331,6 @@ EOF
|
||||
// This selector will be reused when selecting actual tab widget A elements.
|
||||
var tab_a_selector = 'ul.ui-tabs-nav a';
|
||||
|
||||
// This helper will be used to resize tab width
|
||||
var resizeTab = function(oElem){
|
||||
var iTableWidth = (oElem.children('table:first').length > 0) ? oElem.children('table:first').outerWidth() : 0;
|
||||
var oLayoutContentElem = oElem.closest('.ui-layout-content');
|
||||
var bEditMode = (oLayoutContentElem.find('.wizContainer').length > 0);
|
||||
var oContainerElem = (bEditMode) ? oLayoutContentElem.find('.wizContainer:first') : oLayoutContentElem.find('.ui-tabs:first');
|
||||
|
||||
// Resizing wizard container
|
||||
oContainerElem.css('min-width',
|
||||
parseInt(iTableWidth) +
|
||||
parseInt(oElem.css('margin-left'))*2 +
|
||||
parseInt(oElem.css('padding-left'))*2 +
|
||||
parseInt(tabs.css('margin-left'))*2 +
|
||||
parseInt(tabs.css('padding-left'))*2
|
||||
)
|
||||
|
||||
// Resizing header according to content container
|
||||
var iLayoutContentWidth = parseInt(oContainerElem.width());
|
||||
if(bEditMode)
|
||||
{
|
||||
iLayoutContentWidth += parseInt(oContainerElem.css('margin-left'))*2 + parseInt(oContainerElem.css('padding-left'))*2
|
||||
}
|
||||
oLayoutContentElem.find('.page_header').css('min-width', iLayoutContentWidth);
|
||||
};
|
||||
|
||||
// Ugly patch for a change in the behavior of jQuery UI:
|
||||
// Before jQuery UI 1.9, tabs were always considered as "local" (opposed to Ajax)
|
||||
// when their href was beginning by #. Starting with 1.9, a <base> tag in the page
|
||||
@@ -379,9 +354,6 @@ EOF
|
||||
event: 'change', 'show': function(event, ui) {
|
||||
$('.resizable', ui.panel).resizable(); // Make resizable everything that claims to be resizable !
|
||||
},
|
||||
create: function( event, ui ) {
|
||||
resizeTab(ui.panel);
|
||||
},
|
||||
beforeLoad: function( event, ui ) {
|
||||
if ( ui.tab.data('loaded') && (ui.tab.attr('data-cache') == 'true')) {
|
||||
event.preventDefault();
|
||||
@@ -391,9 +363,6 @@ EOF
|
||||
ui.jqXHR.success(function() {
|
||||
ui.tab.data( "loaded", true );
|
||||
});
|
||||
},
|
||||
activate: function( event, ui ) {
|
||||
resizeTab(ui.newPanel);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -148,6 +148,7 @@ class ApplicationMenu
|
||||
// the menu already exists, let's combine the conditions that make it visible
|
||||
self::$aMenusIndex[$index]['node']->AddCondition($oMenuNode);
|
||||
}
|
||||
|
||||
return $index;
|
||||
}
|
||||
|
||||
@@ -174,7 +175,7 @@ class ApplicationMenu
|
||||
{
|
||||
$oMenuNode = self::GetMenuNode($aMenu['index']);
|
||||
if (!$oMenuNode->IsEnabled()) continue; // Don't display a non-enabled menu
|
||||
$oPage->AddToMenu('<h3 id="Menu_'.$oMenuNode->GetMenuID().'">'.$oMenuNode->GetTitle().'</h3>');
|
||||
$oPage->AddToMenu('<h3 id="'.utils::GetSafeId('AccordionMenu_'.$oMenuNode->GetMenuID()).'">'.$oMenuNode->GetTitle().'</h3>');
|
||||
$oPage->AddToMenu('<div>');
|
||||
$aChildren = self::GetChildren($aMenu['index']);
|
||||
if (count($aChildren) > 0)
|
||||
@@ -217,11 +218,11 @@ EOF
|
||||
$sHyperlink = $oMenu->GetHyperlink($aExtraParams);
|
||||
if ($sHyperlink != '')
|
||||
{
|
||||
$oPage->AddToMenu('<li id="Menu_'.$oMenu->GetMenuID().'"'.$sCSSClass.'><a href="'.$oMenu->GetHyperlink($aExtraParams).'">'.$oMenu->GetTitle().'</a></li>');
|
||||
$oPage->AddToMenu('<li id="'.utils::GetSafeId('AccordionMenu_'.$oMenu->GetMenuID()).'"'.$sCSSClass.'><a href="'.$oMenu->GetHyperlink($aExtraParams).'">'.$oMenu->GetTitle().'</a></li>');
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->AddToMenu('<li id="Menu_'.$oMenu->GetMenuID().'"'.$sCSSClass.'>'.$oMenu->GetTitle().'</li>');
|
||||
$oPage->AddToMenu('<li id="'.utils::GetSafeId('AccordionMenu_'.$oMenu->GetMenuID()).'"'.$sCSSClass.'>'.$oMenu->GetTitle().'</li>');
|
||||
}
|
||||
$aCurrentMenu = self::$aMenusIndex[$index];
|
||||
if ($iActiveMenu == $index)
|
||||
@@ -320,6 +321,21 @@ EOF
|
||||
}
|
||||
return $sDefaultMenuId;
|
||||
}
|
||||
|
||||
static public function GetRootMenuId($sMenuId)
|
||||
{
|
||||
$iMenuIndex = self::GetMenuIndexById($sMenuId);
|
||||
if ($iMenuIndex == -1)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
$oMenu = ApplicationMenu::GetMenuNode($iMenuIndex);
|
||||
while ($oMenu->GetParentIndex() != -1)
|
||||
{
|
||||
$oMenu = ApplicationMenu::GetMenuNode($oMenu->GetParentIndex());
|
||||
}
|
||||
return $oMenu->GetMenuId();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -418,7 +434,12 @@ abstract class MenuNode
|
||||
{
|
||||
return $this->sMenuId;
|
||||
}
|
||||
|
||||
|
||||
public function GetParentIndex()
|
||||
{
|
||||
return $this->iParentIndex;
|
||||
}
|
||||
|
||||
public function GetTitle()
|
||||
{
|
||||
return Dict::S("Menu:$this->sMenuId", str_replace('_', ' ', $this->sMenuId));
|
||||
|
||||
@@ -1,49 +1,62 @@
|
||||
<?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/>
|
||||
|
||||
|
||||
/**
|
||||
* File to include to initialize the datamodel in memory
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/core/cmdbobject.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/core/contexttag.class.inc.php');
|
||||
session_name('itop-'.md5(APPROOT));
|
||||
session_start();
|
||||
$sSwitchEnv = utils::ReadParam('switch_env', null);
|
||||
if (($sSwitchEnv != null) && (file_exists(APPCONF.$sSwitchEnv.'/'.ITOP_CONFIG_FILE)))
|
||||
{
|
||||
$_SESSION['itop_env'] = $sSwitchEnv;
|
||||
$sEnv = $sSwitchEnv;
|
||||
// TODO: reset the credentials as well ??
|
||||
}
|
||||
else if (isset($_SESSION['itop_env']))
|
||||
{
|
||||
$sEnv = $_SESSION['itop_env'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sEnv = ITOP_DEFAULT_ENV;
|
||||
$_SESSION['itop_env'] = ITOP_DEFAULT_ENV;
|
||||
}
|
||||
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
|
||||
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, true /* $bAllowCache */, false /* $bTraceSourceFiles */, $sEnv);
|
||||
<?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/>
|
||||
|
||||
|
||||
/**
|
||||
* File to include to initialize the datamodel in memory
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/core/cmdbobject.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/core/contexttag.class.inc.php');
|
||||
session_name('itop-'.md5(APPROOT));
|
||||
session_start();
|
||||
$sSwitchEnv = utils::ReadParam('switch_env', null);
|
||||
$bAllowCache = true;
|
||||
if (($sSwitchEnv != null) && (file_exists(APPCONF.$sSwitchEnv.'/'.ITOP_CONFIG_FILE)) && isset($_SESSION['itop_env']) && ($_SESSION['itop_env'] !== $sSwitchEnv))
|
||||
{
|
||||
$_SESSION['itop_env'] = $sSwitchEnv;
|
||||
$sEnv = $sSwitchEnv;
|
||||
$bAllowCache = false;
|
||||
// Reset the opcache since otherwise the PHP "model" files may still be cached !!
|
||||
if (function_exists('opcache_reset'))
|
||||
{
|
||||
// Zend opcode cache
|
||||
opcache_reset();
|
||||
}
|
||||
if (function_exists('apc_clear_cache'))
|
||||
{
|
||||
// APC(u) cache
|
||||
apc_clear_cache();
|
||||
}
|
||||
// TODO: reset the credentials as well ??
|
||||
}
|
||||
else if (isset($_SESSION['itop_env']))
|
||||
{
|
||||
$sEnv = $_SESSION['itop_env'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sEnv = ITOP_DEFAULT_ENV;
|
||||
$_SESSION['itop_env'] = ITOP_DEFAULT_ENV;
|
||||
}
|
||||
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
|
||||
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
|
||||
@@ -142,7 +142,12 @@ class UIExtKeyWidget
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
}
|
||||
$oAllowedValues->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
if ($oAllowedValues->Count() < $iMaxComboLength)
|
||||
// Don't automatically launch the search if the table is huge
|
||||
$bDoSearch = !utils::IsHighCardinality($this->sTargetClass);
|
||||
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
|
||||
|
||||
// We just need to compare the number of entries with MaxComboLength, so no need to get the real count.
|
||||
if ($oAllowedValues->Count($iMaxComboLength * 2) < $iMaxComboLength)
|
||||
{
|
||||
// Discrete list of values, use a SELECT or RADIO buttons depending on the config
|
||||
switch($sDisplayStyle)
|
||||
@@ -226,7 +231,7 @@ class UIExtKeyWidget
|
||||
}
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode);
|
||||
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
|
||||
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
|
||||
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
|
||||
$('#$this->iId').bind('change', function() { $(this).trigger('extkeychange') } );
|
||||
@@ -261,7 +266,7 @@ EOF
|
||||
$iFieldSize = isset($aArgs['iFieldSize']) ? $aArgs['iFieldSize'] : 20; //@@@ $this->oAttDef->GetMaxSize();
|
||||
|
||||
// the input for the auto-complete
|
||||
$sHTMLValue .= "<input class=\"field_autocomplete\" count=\"".$oAllowedValues->Count()."\" type=\"text\" id=\"label_$this->iId\" value=\"$sDisplayValue\"/>";
|
||||
$sHTMLValue .= "<input class=\"field_autocomplete\" type=\"text\" id=\"label_$this->iId\" value=\"$sDisplayValue\"/>";
|
||||
$sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_search_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_search.gif?itopversion=".ITOP_VERSION."\" onClick=\"oACWidget_{$this->iId}.Search();\"/></span>";
|
||||
|
||||
// another hidden input to store & pass the object's Id
|
||||
@@ -271,7 +276,7 @@ EOF
|
||||
// Scripts to start the autocomplete and bind some events to it
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode);
|
||||
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
|
||||
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
|
||||
$('#label_$this->iId').autocomplete(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { scroll:true, minChars:{$iMinChars}, autoFill:false, matchContains:true, mustMatch: true, keyHolder:'#{$this->iId}', extraParams:{operation:'ac_extkey', sTargetClass:'{$this->sTargetClass}',sFilter:'$sFilter',bSearchMode:$JSSearchMode, json: function() { return $sWizHelperJSON; } }});
|
||||
$('#label_$this->iId').keyup(function() { if ($(this).val() == '') { $('#$this->iId').val(''); } } ); // Useful for search forms: empty value in the "label", means no value, immediatly !
|
||||
@@ -338,7 +343,7 @@ EOF
|
||||
$aParams = array();
|
||||
$oFilter = new DBObjectSearch($this->sTargetClass);
|
||||
}
|
||||
$bOpen = MetaModel::GetConfig()->Get('legacy_search_drawer_open');
|
||||
$bOpen = MetaModel::GetConfig()->Get('legacy_search_drawer_open') || utils::IsHighCardinality($this->sTargetClass);
|
||||
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false, $aParams);
|
||||
$sHTML .= $oBlock->GetDisplay($oPage, $this->iId, array('open' => $bOpen, 'currentId' => $this->iId));
|
||||
@@ -408,14 +413,35 @@ EOF
|
||||
$iCurrentExtKeyId = (is_null($oObj) || $this->sAttCode === '') ? 0 : $oObj->Get($this->sAttCode);
|
||||
|
||||
$oValuesSet = new ValueSetObjects($sFilter, 'friendlyname'); // Bypass GetName() to avoid the encoding by htmlentities
|
||||
$iMax = 150;
|
||||
$oValuesSet->SetLimit($iMax);
|
||||
$oValuesSet->SetSort(false);
|
||||
$oValuesSet->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
|
||||
$aValues = $oValuesSet->GetValues(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains);
|
||||
foreach($aValues as $sKey => $sFriendlyName)
|
||||
|
||||
$aValuesEquals = $oValuesSet->GetValues(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'equals_start_with');
|
||||
//asort($aValuesEquals);
|
||||
foreach($aValuesEquals as $sKey => $sFriendlyName)
|
||||
{
|
||||
$oP->add(trim($sFriendlyName)."\t".$sKey."\n");
|
||||
$iMax--;
|
||||
}
|
||||
if ($iMax <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$oValuesSet->SetLimit($iMax);
|
||||
$aValuesContains = $oValuesSet->GetValues(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'contains');
|
||||
asort($aValuesContains);
|
||||
foreach($aValuesContains as $sKey => $sFriendlyName)
|
||||
{
|
||||
if (!isset($aValuesEquals[$sKey]))
|
||||
{
|
||||
$oP->add(trim($sFriendlyName)."\t".$sKey."\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the display name of the selected object, to fill back the autocomplete
|
||||
*/
|
||||
|
||||
@@ -30,7 +30,14 @@ class UILinksWidgetDirect
|
||||
protected $sInputid;
|
||||
protected $sNameSuffix;
|
||||
protected $sLinkedClass;
|
||||
|
||||
|
||||
/**
|
||||
* UILinksWidgetDirect constructor.
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
* @param string $sInputId
|
||||
* @param string $sNameSuffix
|
||||
*/
|
||||
public function __construct($sClass, $sAttCode, $sInputId, $sNameSuffix = '')
|
||||
{
|
||||
$this->sClass = $sClass;
|
||||
@@ -74,12 +81,12 @@ class UILinksWidgetDirect
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param DBObjectSet $oValue
|
||||
* @param DBObjectSet|ormLinkSet $oValue
|
||||
* @param array $aArgs
|
||||
* @param $sFormPrefix
|
||||
* @param $oCurrentObj
|
||||
* @param string $sFormPrefix
|
||||
* @param DBObject $oCurrentObj
|
||||
*/
|
||||
public function Display(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
|
||||
public function Display(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
|
||||
{
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
switch($oLinksetDef->GetEditMode())
|
||||
@@ -127,11 +134,11 @@ class UILinksWidgetDirect
|
||||
* @param WebPage $oPage
|
||||
* @param DBObjectSet $oValue
|
||||
* @param array $aArgs
|
||||
* @param $sFormPrefix
|
||||
* @param $oCurrentObj
|
||||
* @param $bDisplayMenu
|
||||
* @param string $sFormPrefix
|
||||
* @param DBObject $oCurrentObj
|
||||
* @param bool $bDisplayMenu
|
||||
*/
|
||||
protected function DisplayAsBlock(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $bDisplayMenu)
|
||||
protected function DisplayAsBlock(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $bDisplayMenu)
|
||||
{
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$sTargetClass = $oLinksetDef->GetLinkedClass();
|
||||
@@ -170,50 +177,8 @@ class UILinksWidgetDirect
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param DBObjectSet $oValue
|
||||
* @param array $aArgs
|
||||
* @param $sFormPrefix
|
||||
* @param $oCurrentObj
|
||||
* @param array $aButtons
|
||||
* @param string $sProposedRealClass
|
||||
*/
|
||||
protected function DisplayEditInPlace(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
|
||||
{
|
||||
$aAttribs = $this->GetTableConfig();
|
||||
|
||||
$oValue->Rewind();
|
||||
$oPage->add('<table class="listContainer" id="'.$this->sInputid.'"><tr><td>');
|
||||
|
||||
$aData = array();
|
||||
while($oLinkObj = $oValue->Fetch())
|
||||
{
|
||||
$aRow = array();
|
||||
$aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.$oLinkObj->GetKey().'"/>';
|
||||
foreach($this->aZlist as $sLinkedAttCode)
|
||||
{
|
||||
$aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode);
|
||||
}
|
||||
$aData[] = $aRow;
|
||||
}
|
||||
$oPage->table($aAttribs, $aData);
|
||||
$oPage->add('</td></tr></table>'); //listcontainer
|
||||
$sInputName = $sFormPrefix.'attr_'.$this->sAttCode;
|
||||
$aLabels = array(
|
||||
'delete' => Dict::S('UI:Button:Delete'),
|
||||
// 'modify' => 'Modify...' ,
|
||||
'creation_title' => Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
'create' => Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($this->sLinkedClass)),
|
||||
'remove' => Dict::S('UI:Button:Remove'),
|
||||
'add' => Dict::Format('UI:AddAnExisting_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
'selection_title' => Dict::Format('UI:SelectionOf_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
);
|
||||
$oContext = new ApplicationContext();
|
||||
$sSubmitUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?'.$oContext->GetForLink();
|
||||
$sJSONLabels = json_encode($aLabels);
|
||||
$sJSONButtons = json_encode($aButtons);
|
||||
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
$oPage->add_ready_script("$('#{$this->sInputid}').directlinks({class_name: '$this->sClass', att_code: '$this->sAttCode', input_name:'$sInputName', labels: $sJSONLabels, submit_to: '$sSubmitUrl', buttons: $sJSONButtons, oWizardHelper: $sWizHelper });");
|
||||
}
|
||||
|
||||
public function GetObjectCreationDlg(WebPage $oPage, $sProposedRealClass = '')
|
||||
{
|
||||
// For security reasons: check that the "proposed" class is actually a subclass of the linked class
|
||||
@@ -239,14 +204,14 @@ class UILinksWidgetDirect
|
||||
$aKeys = array_keys($aPossibleClasses);
|
||||
$sRealClass = $aKeys[0];
|
||||
}
|
||||
|
||||
|
||||
if ($sRealClass != '')
|
||||
{
|
||||
$oPage->add("<h1>".MetaModel::GetClassIcon($sRealClass)." ".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($sRealClass))."</h1>\n");
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$sExtKeyToMe = $oLinksetDef->GetExtKeyToMe();
|
||||
$aFieldFlags = array( $sExtKeyToMe => OPT_ATT_HIDDEN);
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $sRealClass, null, array(), array('formPrefix' => $this->sInputid, 'noRelations' => true, 'fieldsFlags' => $aFieldFlags));
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $sRealClass, null, array(), array('formPrefix' => $this->sInputid, 'noRelations' => true, 'fieldsFlags' => $aFieldFlags));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -263,7 +228,61 @@ class UILinksWidgetDirect
|
||||
}
|
||||
$oPage->add('</div></div>');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param DBObjectSet $oValue
|
||||
* @param array $aArgs
|
||||
* @param string $sFormPrefix
|
||||
* @param DBObject $oCurrentObj
|
||||
* @param array $aButtons
|
||||
*/
|
||||
protected function DisplayEditInPlace(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
|
||||
{
|
||||
$aAttribs = $this->GetTableConfig();
|
||||
|
||||
$oValue->Rewind();
|
||||
$oPage->add('<table class="listContainer" id="'.$this->sInputid.'"><tr><td>');
|
||||
|
||||
$aData = array();
|
||||
while($oLinkObj = $oValue->Fetch())
|
||||
{
|
||||
$aRow = array();
|
||||
$aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.$oLinkObj->GetKey().'"/>';
|
||||
foreach($this->aZlist as $sLinkedAttCode)
|
||||
{
|
||||
$aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode);
|
||||
}
|
||||
$aData[] = $aRow;
|
||||
}
|
||||
$oPage->table($aAttribs, $aData);
|
||||
$oPage->add('</td></tr></table>'); //listcontainer
|
||||
$sInputName = $sFormPrefix.'attr_'.$this->sAttCode;
|
||||
$aLabels = array(
|
||||
'delete' => Dict::S('UI:Button:Delete'),
|
||||
// 'modify' => 'Modify...' ,
|
||||
'creation_title' => Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
'create' => Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($this->sLinkedClass)),
|
||||
'remove' => Dict::S('UI:Button:Remove'),
|
||||
'add' => Dict::Format('UI:AddAnExisting_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
'selection_title' => Dict::Format('UI:SelectionOf_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
);
|
||||
$oContext = new ApplicationContext();
|
||||
$sSubmitUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?'.$oContext->GetForLink();
|
||||
$sJSONLabels = json_encode($aLabels);
|
||||
$sJSONButtons = json_encode($aButtons);
|
||||
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
// Don't automatically launch the search if the table is huge
|
||||
$bDoSearch = !utils::IsHighCardinality($this->sLinkedClass);
|
||||
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
|
||||
$oPage->add_ready_script("$('#{$this->sInputid}').directlinks({class_name: '$this->sClass', att_code: '$this->sAttCode', input_name:'$sInputName', labels: $sJSONLabels, submit_to: '$sSubmitUrl', buttons: $sJSONButtons, oWizardHelper: $sWizHelper, do_search: $sJSDoSearch});");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param DBObject $oCurrentObj
|
||||
* @throws Exception
|
||||
*/
|
||||
public function GetObjectsSelectionDlg($oPage, $oCurrentObj)
|
||||
{
|
||||
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
|
||||
@@ -286,7 +305,7 @@ class UILinksWidgetDirect
|
||||
{
|
||||
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
|
||||
}
|
||||
$bOpen = MetaModel::GetConfig()->Get('legacy_search_drawer_open');
|
||||
$bOpen = MetaModel::GetConfig()->Get('legacy_search_drawer_open') || utils::IsHighCardinality($this->sLinkedClass);
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}", array('open' => $bOpen));
|
||||
$sHtml .= "<form id=\"ObjectsAddForm_{$this->sInputid}\">\n";
|
||||
@@ -299,13 +318,14 @@ class UILinksWidgetDirect
|
||||
$sHtml .= "</form>\n";
|
||||
$oPage->add($sHtml);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Search for objects to be linked to the current object (i.e "remote" objects)
|
||||
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
|
||||
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of $this->sLinkedClass
|
||||
* @param array $aAlreadyLinked Array of indentifiers of objects which are already linke to the current object (or about to be linked)
|
||||
* @param DBObject $oCurrentObj The object currently being edited... if known...
|
||||
* @throws Exception
|
||||
*/
|
||||
public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinked = array(), $oCurrentObj = null)
|
||||
{
|
||||
@@ -350,6 +370,10 @@ class UILinksWidgetDirect
|
||||
$oBlock->Display($oP, "ResultsToAdd_{$this->sInputid}", array('menu' => false, 'cssCount'=> '#count_'.$this->sInputid , 'selection_mode' => true, 'table_id' => 'add_'.$this->sInputid)); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oP
|
||||
* @param $oFullSetFilter
|
||||
*/
|
||||
public function DoAddObjects(WebPage $oP, $oFullSetFilter)
|
||||
{
|
||||
$aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter);
|
||||
@@ -377,7 +401,14 @@ class UILinksWidgetDirect
|
||||
}
|
||||
return $aAttribs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param string $sRealClass
|
||||
* @param array $aValues
|
||||
* @param int $iTempId
|
||||
* @return mixed
|
||||
*/
|
||||
public function GetRow($oPage, $sRealClass, $aValues, $iTempId)
|
||||
{
|
||||
if ($sRealClass == '')
|
||||
@@ -389,7 +420,13 @@ class UILinksWidgetDirect
|
||||
|
||||
return $this->GetObjectRow($oPage, $oLinkObj, $iTempId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param $oLinkObj
|
||||
* @param int $iTempId
|
||||
* @return mixed
|
||||
*/
|
||||
protected function GetObjectRow($oPage, $oLinkObj, $iTempId)
|
||||
{
|
||||
$aAttribs = $this->GetTableConfig();
|
||||
@@ -405,7 +442,7 @@ class UILinksWidgetDirect
|
||||
/**
|
||||
* Initializes the default search parameters based on 1) a 'current' object and 2) the silos defined by the context
|
||||
* @param DBObject $oSourceObj
|
||||
* @param DBSearch $oSearch
|
||||
* @param DBSearch|DBObjectSearch $oSearch
|
||||
*/
|
||||
protected function SetSearchDefaultFromContext($oSourceObj, &$oSearch)
|
||||
{
|
||||
@@ -424,7 +461,6 @@ class UILinksWidgetDirect
|
||||
|
||||
if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sSrcClass, $sAttCode);
|
||||
$defaultValue = $oSourceObj->Get($sAttCode);
|
||||
|
||||
// Find the attcode for the same 'context' parameter in the destination class
|
||||
|
||||
@@ -39,7 +39,15 @@ class UILinksWidget
|
||||
protected $m_sLinkedClass;
|
||||
protected $m_sRemoteClass;
|
||||
protected $m_bDuplicatesAllowed;
|
||||
|
||||
|
||||
/**
|
||||
* UILinksWidget constructor.
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
* @param int $iInputId
|
||||
* @param string $sNameSuffix
|
||||
* @param bool $bDuplicatesAllowed
|
||||
*/
|
||||
public function __construct($sClass, $sAttCode, $iInputId, $sNameSuffix = '', $bDuplicatesAllowed = false)
|
||||
{
|
||||
$this->m_sClass = $sClass;
|
||||
@@ -98,11 +106,11 @@ class UILinksWidget
|
||||
* @param WebPage $oP Web page used for the ouput
|
||||
* @param DBObject $oLinkedObj Remote object
|
||||
* @param mixed $linkObjOrId Either the object linked or a unique number for new link records to add
|
||||
* @param array|Hash $aArgs Extra context arguments
|
||||
* @param $oCurrentObj The object to which all the elements of the linked set refer to
|
||||
* @param $iUniqueId A unique identifier of new links
|
||||
* @param boolean $bReadOnly Display link as editable or read-only. Default is false (editable)
|
||||
* @return string The HTML fragment of the one-row form
|
||||
* @param array $aArgs Extra context arguments
|
||||
* @param DBObject $oCurrentObj The object to which all the elements of the linked set refer to
|
||||
* @param int $iUniqueId A unique identifier of new links
|
||||
* @param boolean $bReadOnly Display link as editable or read-only. Default is false (editable)
|
||||
* @return array The HTML fragment of the one-row form
|
||||
*/
|
||||
protected function GetFormRow(WebPage $oP, DBObject $oLinkedObj, $linkObjOrId, $aArgs, $oCurrentObj, $iUniqueId, $bReadOnly = false)
|
||||
{
|
||||
@@ -138,7 +146,9 @@ class UILinksWidget
|
||||
$sValue = $linkObjOrId->Get($sFieldCode);
|
||||
$sDisplayValue = $linkObjOrId->GetEditValue($sFieldCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
|
||||
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $sValue, $sDisplayValue, $sSafeId, $sNameSuffix, 0, $aArgs);
|
||||
$aRow[$sFieldCode] = '<div class="field_container" style="border:none;"><div class="field_data"><div class="field_value">'.
|
||||
cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $sValue, $sDisplayValue, $sSafeId, $sNameSuffix, 0, $aArgs).
|
||||
'</div></div></div>';
|
||||
$aFieldsMap[$sFieldCode] = $sSafeId;
|
||||
}
|
||||
}
|
||||
@@ -166,7 +176,7 @@ class UILinksWidget
|
||||
$sPrefix .= "[-$iUniqueId][";
|
||||
$sNameSuffix = "]"; // To make a tabular form
|
||||
$aArgs['prefix'] = $sPrefix;
|
||||
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}_".$iUniqueId;
|
||||
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}_".($iUniqueId < 0 ? -$iUniqueId : $iUniqueId);
|
||||
$aArgs['this'] = $oNewLinkObj;
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"-$iUniqueId\">";
|
||||
foreach($this->m_aEditableFields as $sFieldCode)
|
||||
@@ -176,17 +186,24 @@ class UILinksWidget
|
||||
$sValue = $oNewLinkObj->Get($sFieldCode);
|
||||
$sDisplayValue = $oNewLinkObj->GetEditValue($sFieldCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
|
||||
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $sValue, $sDisplayValue, $sSafeId /* id */, $sNameSuffix, 0, $aArgs);
|
||||
$aRow[$sFieldCode] = '<div class="field_container" style="border:none;"><div class="field_data"><div class="field_value">'.
|
||||
cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $sValue, $sDisplayValue, $sSafeId /* id */, $sNameSuffix, 0, $aArgs).
|
||||
'</div></div></div>';
|
||||
$aFieldsMap[$sFieldCode] = $sSafeId;
|
||||
}
|
||||
$sState = '';
|
||||
|
||||
$oP->add_script(
|
||||
<<<EOF
|
||||
// Rows created with ajax call need OnLinkAdded call.
|
||||
// Rows added before loading the form cannot call OnLinkAdded.
|
||||
if ($iUniqueId > 0)
|
||||
{
|
||||
$oP->add_script(
|
||||
<<<EOF
|
||||
PrepareWidgets();
|
||||
oWidget{$this->m_iInputId}.OnLinkAdded($iUniqueId, $iRemoteObjKey);
|
||||
EOF
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if(!$bReadOnly)
|
||||
@@ -220,7 +237,11 @@ EOF
|
||||
|
||||
/**
|
||||
* Display one row of the whole form
|
||||
* @return none
|
||||
* @param WebPage $oP
|
||||
* @param array $aConfig
|
||||
* @param array $aRow
|
||||
* @param int $iRowId
|
||||
* @return string
|
||||
*/
|
||||
protected function DisplayFormRow(WebPage $oP, $aConfig, $aRow, $iRowId)
|
||||
{
|
||||
@@ -238,8 +259,8 @@ EOF
|
||||
/**
|
||||
* Display the table with the form for editing all the links at once
|
||||
* @param WebPage $oP The web page used for the output
|
||||
* @param Hash $aConfig The table's header configuration
|
||||
* @param Hash $aData The tabular data to be displayed
|
||||
* @param array $aConfig The table's header configuration
|
||||
* @param array $aData The tabular data to be displayed
|
||||
* @return string Html fragment representing the form table
|
||||
*/
|
||||
protected function DisplayFormTable(WebPage $oP, $aConfig, $aData)
|
||||
@@ -276,21 +297,20 @@ EOF
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the HTML fragment corresponding to the linkset editing widget
|
||||
* @param WebPage $oP The web page used for all the output
|
||||
* @param DBObjectSet The initial value of the linked set
|
||||
* @param Hash $aArgs Extra context arguments
|
||||
* @param WebPage $oPage
|
||||
* @param DBObject|ormLinkSet $oValue
|
||||
* @param array $aArgs Extra context arguments
|
||||
* @param string $sFormPrefix prefix of the fields in the current form
|
||||
* @param DBObject $oCurrentObj the current object to which the linkset is related
|
||||
* @return string The HTML fragment to be inserted into the page
|
||||
*/
|
||||
public function Display(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
|
||||
public function Display(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
|
||||
{
|
||||
$sHtmlValue = '';
|
||||
$sTargetClass = self::GetTargetClass($this->m_sClass, $this->m_sAttCode);
|
||||
$sHtmlValue .= "<div id=\"linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix}\">\n";
|
||||
$sHtmlValue .= "<input type=\"hidden\" id=\"{$sFormPrefix}{$this->m_iInputId}\">\n";
|
||||
$oValue->Rewind();
|
||||
@@ -324,9 +344,12 @@ EOF
|
||||
}
|
||||
$sHtmlValue .= $this->DisplayFormTable($oPage, $this->m_aTableConfig, $aForm);
|
||||
$sDuplicates = ($this->m_bDuplicatesAllowed) ? 'true' : 'false';
|
||||
// Don't automatically launch the search if the table is huge
|
||||
$bDoSearch = !utils::IsHighCardinality($this->m_sRemoteClass);
|
||||
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
|
||||
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
$oPage->add_ready_script(<<<EOF
|
||||
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates, $sWizHelper, '{$this->m_sExtKeyToRemote}');
|
||||
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates, $sWizHelper, '{$this->m_sExtKeyToRemote}', $sJSDoSearch);
|
||||
oWidget{$this->m_iInputId}.Init();
|
||||
EOF
|
||||
);
|
||||
@@ -337,11 +360,17 @@ EOF
|
||||
$oPage->add_at_the_end("<div id=\"dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}\"></div>"); // To prevent adding forms inside the main form
|
||||
return $sHtmlValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode
|
||||
* @return string
|
||||
*/
|
||||
protected static function GetTargetClass($sClass, $sAttCode)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$sLinkedClass = $oAttDef->GetLinkedClass();
|
||||
$sTargetClass = '';
|
||||
switch(get_class($oAttDef))
|
||||
{
|
||||
case 'AttributeLinkedSetIndirect':
|
||||
@@ -356,10 +385,14 @@ EOF
|
||||
|
||||
return $sTargetClass;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param DBObject $oCurrentObj
|
||||
*/
|
||||
public function GetObjectPickerDialog($oPage, $oCurrentObj)
|
||||
{
|
||||
$bOpen = MetaModel::GetConfig()->Get('legacy_search_drawer_open');
|
||||
$bOpen = MetaModel::GetConfig()->Get('legacy_search_drawer_open') || utils::IsHighCardinality($this->m_sRemoteClass);
|
||||
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
|
||||
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
|
||||
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
|
||||
@@ -405,7 +438,13 @@ EOF
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, "ResultsToAdd_{$this->m_sAttCode}", array('menu' => false, 'cssCount'=> '#count_'.$this->m_sAttCode.$this->m_sNameSuffix , 'selection_mode' => true, 'table_id' => 'add_'.$this->m_sAttCode)); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param WebPage $oP
|
||||
* @param int $iMaxAddedId
|
||||
* @param $oFullSetFilter
|
||||
* @param DBObject $oCurrentObj
|
||||
*/
|
||||
public function DoAddObjects(WebPage $oP, $iMaxAddedId, $oFullSetFilter, $oCurrentObj)
|
||||
{
|
||||
$aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter);
|
||||
@@ -430,7 +469,7 @@ EOF
|
||||
/**
|
||||
* Initializes the default search parameters based on 1) a 'current' object and 2) the silos defined by the context
|
||||
* @param DBObject $oSourceObj
|
||||
* @param DBSearch $oSearch
|
||||
* @param DBSearch|DBObjectSearch $oSearch
|
||||
*/
|
||||
protected function SetSearchDefaultFromContext($oSourceObj, &$oSearch)
|
||||
{
|
||||
@@ -449,7 +488,6 @@ EOF
|
||||
|
||||
if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sSrcClass, $sAttCode);
|
||||
$defaultValue = $oSourceObj->Get($sAttCode);
|
||||
|
||||
// Find the attcode for the same 'context' parameter in the destination class
|
||||
|
||||
@@ -141,6 +141,9 @@ class utils
|
||||
}
|
||||
|
||||
protected static $bPageMode = null;
|
||||
/**
|
||||
* @var boolean[]
|
||||
*/
|
||||
protected static $aModes = array();
|
||||
|
||||
public static function InitArchiveMode()
|
||||
@@ -164,6 +167,10 @@ class utils
|
||||
self::$bPageMode = ($iCurrent == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean $bMode if true then activate archive mode (archived objects are visible), otherwise archived objects are
|
||||
* hidden (archive = "soft deletion")
|
||||
*/
|
||||
public static function PushArchiveMode($bMode)
|
||||
{
|
||||
array_push(self::$aModes, $bMode);
|
||||
@@ -174,6 +181,9 @@ class utils
|
||||
array_pop(self::$aModes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean true if archive mode is enabled
|
||||
*/
|
||||
public static function IsArchiveMode()
|
||||
{
|
||||
if (count(self::$aModes) > 0)
|
||||
@@ -605,16 +615,20 @@ class utils
|
||||
{
|
||||
if (self::$oConfig == null)
|
||||
{
|
||||
$sConfigFile = self::GetConfigFilePath();
|
||||
if (file_exists($sConfigFile))
|
||||
{
|
||||
self::$oConfig = new Config($sConfigFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
// When executing the setup, the config file may be still missing
|
||||
self::$oConfig = new Config();
|
||||
}
|
||||
self::$oConfig = MetaModel::GetConfig();
|
||||
if (self::$oConfig == null)
|
||||
{
|
||||
$sConfigFile = self::GetConfigFilePath();
|
||||
if (file_exists($sConfigFile))
|
||||
{
|
||||
self::$oConfig = new Config($sConfigFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
// When executing the setup, the config file may be still missing
|
||||
self::$oConfig = new Config();
|
||||
}
|
||||
}
|
||||
}
|
||||
return self::$oConfig;
|
||||
}
|
||||
@@ -917,7 +931,7 @@ class utils
|
||||
*/
|
||||
public static function GetCachePath()
|
||||
{
|
||||
return APPROOT.'data/cache-'.self::GetCurrentEnvironment().'/';
|
||||
return APPROOT.'data/cache-'.MetaModel::GetEnvironment().'/';
|
||||
}
|
||||
/**
|
||||
* Merge standard menu items with plugin provided menus items
|
||||
@@ -957,8 +971,8 @@ class utils
|
||||
// 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:AddToDashboard', Dict::S('UI:Menu:AddToDashboard'), "DashletCreationDlg('$sOQL')");
|
||||
}
|
||||
$aResult[] = new JSPopupMenuItem('UI:Menu:AddToDashboard', Dict::S('UI:Menu:AddToDashboard'), "DashletCreationDlg('$sOQL', '$sContext')");
|
||||
$aResult[] = new JSPopupMenuItem('UI:Menu:ShortcutList', Dict::S('UI:Menu:ShortcutList'), "ShortcutListDlg('$sOQL', '$sDataTableId', '$sContext')");
|
||||
|
||||
break;
|
||||
@@ -1054,8 +1068,7 @@ class utils
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute URL to the modules root path
|
||||
* @return string ...
|
||||
* @return string the absolute URL to the modules root path
|
||||
*/
|
||||
static public function GetAbsoluteUrlModulesRoot()
|
||||
{
|
||||
@@ -1063,33 +1076,67 @@ class utils
|
||||
return $sUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL to a page that will execute the requested module page
|
||||
*
|
||||
* To be compatible with this mechanism, the called page must include approot
|
||||
* with an absolute path OR not include it at all (losing the direct access to the page)
|
||||
* if (!defined('__DIR__')) define('__DIR__', dirname(__FILE__));
|
||||
* require_once(__DIR__.'/../../approot.inc.php');
|
||||
*
|
||||
* @return string ...
|
||||
*/
|
||||
/**
|
||||
* To be compatible with this mechanism, the called page must include approot with an absolute path OR not include
|
||||
* it at all (losing the direct access to the page) :
|
||||
*
|
||||
* ```php
|
||||
* if (!defined('__DIR__')) define('__DIR__', dirname(__FILE__));
|
||||
* require_once(__DIR__.'/../../approot.inc.php');
|
||||
* ```
|
||||
*
|
||||
* @param string $sModule
|
||||
* @param string $sPage
|
||||
* @param string[] $aArguments
|
||||
* @param string $sEnvironment
|
||||
*
|
||||
* @return string the URL to a page that will execute the requested module page, with query string values url encoded
|
||||
*
|
||||
* @see GetExecPageArguments can be used to submit using the GET method (see bug in N.1108)
|
||||
* @see GetAbsoluteUrlExecPage
|
||||
*/
|
||||
static public function GetAbsoluteUrlModulePage($sModule, $sPage, $aArguments = array(), $sEnvironment = null)
|
||||
{
|
||||
$aArgs = self::GetExecPageArguments($sModule, $sPage, $aArguments, $sEnvironment);
|
||||
$sArgs = http_build_query($aArgs);
|
||||
|
||||
return self::GetAbsoluteUrlExecPage()."?".$sArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sModule
|
||||
* @param string $sPage
|
||||
* @param string[] $aArguments
|
||||
* @param string $sEnvironment
|
||||
*
|
||||
* @return string[] key/value pair for the exec page query string. <b>Warning</b> : values are not url encoded !
|
||||
* @throws \Exception if one of the argument has a reserved name
|
||||
*/
|
||||
static public function GetExecPageArguments($sModule, $sPage, $aArguments = array(), $sEnvironment = null)
|
||||
{
|
||||
$sEnvironment = is_null($sEnvironment) ? self::GetCurrentEnvironment() : $sEnvironment;
|
||||
$aArgs = array();
|
||||
$aArgs[] = 'exec_module='.$sModule;
|
||||
$aArgs[] = 'exec_page='.$sPage;
|
||||
$aArgs[] = 'exec_env='.$sEnvironment;
|
||||
$aArgs['exec_module'] = $sModule;
|
||||
$aArgs['exec_page'] = $sPage;
|
||||
$aArgs['exec_env'] = $sEnvironment;
|
||||
foreach($aArguments as $sName => $sValue)
|
||||
{
|
||||
if (($sName == 'exec_module')||($sName == 'exec_page')||($sName == 'exec_env'))
|
||||
if (($sName == 'exec_module') || ($sName == 'exec_page') || ($sName == 'exec_env'))
|
||||
{
|
||||
throw new Exception("Module page: $sName is a reserved page argument name");
|
||||
}
|
||||
$aArgs[] = $sName.'='.urlencode($sValue);
|
||||
$aArgs[$sName] = $sValue;
|
||||
}
|
||||
$sArgs = implode('&', $aArgs);
|
||||
return self::GetAbsoluteUrlAppRoot().'pages/exec.php?'.$sArgs;
|
||||
|
||||
return $aArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
static public function GetAbsoluteUrlExecPage()
|
||||
{
|
||||
return self::GetAbsoluteUrlAppRoot().'pages/exec.php';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1590,4 +1637,220 @@ class utils
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given path/url is an http(s) URL
|
||||
* @param string $sPath
|
||||
* @return boolean
|
||||
*/
|
||||
public static function IsURL($sPath)
|
||||
{
|
||||
$bRet = false;
|
||||
if ((substr($sPath, 0, 7) == 'http://') || (substr($sPath, 0, 8) == 'https://') || (substr($sPath, 0, 8) == 'ftp://'))
|
||||
{
|
||||
$bRet = true;
|
||||
}
|
||||
return $bRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given URL is a link to download a document/image on the CURRENT iTop
|
||||
* In such a case we can read the content of the file directly in the database (if the users rights allow) and return the ormDocument
|
||||
* @param string $sPath
|
||||
* @return false|ormDocument
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function IsSelfURL($sPath)
|
||||
{
|
||||
$result = false;
|
||||
$sPageUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.document.php';
|
||||
if (substr($sPath, 0, strlen($sPageUrl)) == $sPageUrl)
|
||||
{
|
||||
// If the URL is an URL pointing to this instance of iTop, then
|
||||
// extract the "query" part of the URL and analyze it
|
||||
$sQuery = parse_url($sPath, PHP_URL_QUERY);
|
||||
if ($sQuery !== null)
|
||||
{
|
||||
$aParams = array();
|
||||
foreach(explode('&', $sQuery) as $sChunk)
|
||||
{
|
||||
$aParts = explode('=', $sChunk);
|
||||
if (count($aParts) != 2) continue;
|
||||
$aParams[$aParts[0]] = urldecode($aParts[1]);
|
||||
}
|
||||
$result = array_key_exists('operation', $aParams) && array_key_exists('class', $aParams) && array_key_exists('id', $aParams) && array_key_exists('field', $aParams) && ($aParams['operation'] == 'download_document');
|
||||
if ($result)
|
||||
{
|
||||
// This is a 'download_document' operation, let's retrieve the document directly from the database
|
||||
$sClass = $aParams['class'];
|
||||
$iKey = $aParams['id'];
|
||||
$sAttCode = $aParams['field'];
|
||||
|
||||
$oObj = MetaModel::GetObject($sClass, $iKey, false /* must exist */); // Users rights apply here !!
|
||||
if ($oObj)
|
||||
{
|
||||
/**
|
||||
* @var ormDocument $result
|
||||
*/
|
||||
$result = clone $oObj->Get($sAttCode);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Exception('Invalid URL. This iTop URL is not pointing to a valid Document/Image.');
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the content of a file (and retrieve its MIME type) from either:
|
||||
* - an URL pointing to a blob (image/document) on the current iTop server
|
||||
* - an http(s) URL
|
||||
* - the local file system (but only if you are an administrator)
|
||||
* @param string $sPath
|
||||
* @return ormDocument|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function FileGetContentsAndMIMEType($sPath)
|
||||
{
|
||||
$oUploadedDoc = null;
|
||||
$aKnownExtensions = array(
|
||||
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
|
||||
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
|
||||
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
|
||||
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
|
||||
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
|
||||
'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
|
||||
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
|
||||
'jpg' => 'image/jpeg',
|
||||
'jpeg' => 'image/jpeg',
|
||||
'gif' => 'image/gif',
|
||||
'png' => 'image/png',
|
||||
'pdf' => 'application/pdf',
|
||||
'doc' => 'application/msword',
|
||||
'dot' => 'application/msword',
|
||||
'xls' => 'application/vnd.ms-excel',
|
||||
'ppt' => 'application/vnd.ms-powerpoint',
|
||||
'vsd' => 'application/x-visio',
|
||||
'vdx' => 'application/visio.drawing',
|
||||
'odt' => 'application/vnd.oasis.opendocument.text',
|
||||
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
|
||||
'odp' => 'application/vnd.oasis.opendocument.presentation',
|
||||
'zip' => 'application/zip',
|
||||
'txt' => 'text/plain',
|
||||
'htm' => 'text/html',
|
||||
'html' => 'text/html',
|
||||
'exe' => 'application/octet-stream'
|
||||
);
|
||||
|
||||
$sData = null;
|
||||
$sMimeType = 'text/plain'; // Default MIME Type: treat the file as a bunch a characters...
|
||||
$sFileName = 'uploaded-file'; // Default name for downloaded-files
|
||||
$sExtension = '.txt'; // Default file extension in case we don't know the MIME Type
|
||||
|
||||
if(empty($sPath))
|
||||
{
|
||||
// Empty path (NULL or '') means that there is no input, making an empty document.
|
||||
$oUploadedDoc = new ormDocument('', '', '');
|
||||
}
|
||||
elseif (static::IsURL($sPath))
|
||||
{
|
||||
if ($oUploadedDoc = static::IsSelfURL($sPath))
|
||||
{
|
||||
// Nothing more to do, we've got it !!
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remote file, let's use the HTTP headers to find the MIME Type
|
||||
$sData = @file_get_contents($sPath);
|
||||
if ($sData === false)
|
||||
{
|
||||
throw new Exception("Failed to load the file from the URL '$sPath'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($http_response_header))
|
||||
{
|
||||
$aHeaders = static::ParseHeaders($http_response_header);
|
||||
$sMimeType = array_key_exists('Content-Type', $aHeaders) ? strtolower($aHeaders['Content-Type']) : 'application/x-octet-stream';
|
||||
// Compute the file extension from the MIME Type
|
||||
foreach($aKnownExtensions as $sExtValue => $sMime)
|
||||
{
|
||||
if ($sMime === $sMimeType)
|
||||
{
|
||||
$sExtension = '.'.$sExtValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$sFileName .= $sExtension;
|
||||
}
|
||||
$oUploadedDoc = new ormDocument($sData, $sMimeType, $sFileName);
|
||||
}
|
||||
}
|
||||
else if (UserRights::IsAdministrator())
|
||||
{
|
||||
// Only administrators are allowed to read local files
|
||||
$sData = @file_get_contents($sPath);
|
||||
if ($sData === false)
|
||||
{
|
||||
throw new Exception("Failed to load the file '$sPath'. The file does not exist or the current process is not allowed to access it.");
|
||||
}
|
||||
$sExtension = strtolower(pathinfo($sPath, PATHINFO_EXTENSION));
|
||||
$sFileName = basename($sPath);
|
||||
|
||||
if (array_key_exists($sExtension, $aKnownExtensions))
|
||||
{
|
||||
$sMimeType = $aKnownExtensions[$sExtension];
|
||||
}
|
||||
else if (extension_loaded('fileinfo'))
|
||||
{
|
||||
$finfo = new finfo(FILEINFO_MIME);
|
||||
$sMimeType = $finfo->file($sPath);
|
||||
}
|
||||
$oUploadedDoc = new ormDocument($sData, $sMimeType, $sFileName);
|
||||
}
|
||||
return $oUploadedDoc;
|
||||
}
|
||||
|
||||
protected static function ParseHeaders($aHeaders)
|
||||
{
|
||||
$aCleanHeaders = array();
|
||||
foreach( $aHeaders as $sKey => $sValue )
|
||||
{
|
||||
$aTokens = explode(':', $sValue, 2);
|
||||
if(isset($aTokens[1]))
|
||||
{
|
||||
$aCleanHeaders[trim($aTokens[0])] = trim($aTokens[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The header is not in the form Header-Code: Value
|
||||
$aCleanHeaders[] = $sValue; // Store the value as-is
|
||||
$aMatches = array();
|
||||
// Check if it's not the HTTP response code
|
||||
if( preg_match("|HTTP/[0-9\.]+\s+([0-9]+)|", $sValue, $aMatches) )
|
||||
{
|
||||
$aCleanHeaders['reponse_code'] = intval($aMatches[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aCleanHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given class if configured as a high cardinality class.
|
||||
*
|
||||
* @param $sClass
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function IsHighCardinality($sClass)
|
||||
{
|
||||
$aHugeClasses = MetaModel::GetConfig()->Get('high_cardinality_classes');
|
||||
return in_array($sClass, $aHugeClasses);
|
||||
}
|
||||
}
|
||||
|
||||
10
composer.json
Normal file
10
composer.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"require": {
|
||||
"php": ">=5.3.6 <7.2.0"
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "5.3.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2016 Combodo SARL
|
||||
// Copyright (C) 2016-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -67,3 +67,32 @@ if (!function_exists('apc_store') && function_exists('apcu_store'))
|
||||
return apcu_store($key, $var, $ttl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns user cache info... beware of the format of the returned structure that may vary (See usages)
|
||||
* @return array
|
||||
*/
|
||||
function apc_cache_info_compat()
|
||||
{
|
||||
if (!function_exists('apc_cache_info')) return array();
|
||||
|
||||
$oFunction = new ReflectionFunction('apc_cache_info');
|
||||
if ($oFunction->getNumberOfParameters() != 2)
|
||||
{
|
||||
// Beware: APCu behaves slightly differently from APC !!
|
||||
// Worse: the compatibility layer integrated into APC differs from apcu-bc (testing the number of parameters is a must)
|
||||
// In CLI mode (PHP > 7) apc_cache_info returns null and outputs an error message.
|
||||
$aCacheUserData = @apc_cache_info();
|
||||
}
|
||||
else
|
||||
{
|
||||
$aCacheUserData = @apc_cache_info('user');
|
||||
}
|
||||
return $aCacheUserData;
|
||||
}
|
||||
|
||||
// Cache emulation
|
||||
if (!function_exists('apc_store'))
|
||||
{
|
||||
require_once(APPROOT.'core/apc-emulation.php');
|
||||
}
|
||||
301
core/apc-emulation.php
Normal file
301
core/apc-emulation.php
Normal file
@@ -0,0 +1,301 @@
|
||||
<?php
|
||||
// Copyright (c) 2010-2017 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/>
|
||||
//
|
||||
|
||||
/**
|
||||
* Date: 27/09/2017
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param string $cache_type
|
||||
* @param bool $limited
|
||||
* @return array|bool
|
||||
*/
|
||||
function apc_cache_info($cache_type = '', $limited = false)
|
||||
{
|
||||
$aInfo = array();
|
||||
$sRootCacheDir = apc_emul_get_cache_filename('');
|
||||
$aInfo['cache_list'] = apc_emul_get_cache_entries($sRootCacheDir);
|
||||
return $aInfo;
|
||||
}
|
||||
|
||||
function apc_emul_get_cache_entries($sEntry)
|
||||
{
|
||||
$aResult = array();
|
||||
if (is_dir($sEntry))
|
||||
{
|
||||
$aFiles = array_diff(scandir($sEntry), array('.', '..'));
|
||||
foreach($aFiles as $sFile)
|
||||
{
|
||||
$sSubFile = $sEntry.'/'.$sFile;
|
||||
$aResult = array_merge($aResult, apc_emul_get_cache_entries($sSubFile));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$sKey = basename($sEntry);
|
||||
if (strpos($sKey, '-') === 0)
|
||||
{
|
||||
$sKey = substr($sKey, 1);
|
||||
}
|
||||
$aResult[] = array('info' => $sKey);
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $key
|
||||
* @param $var
|
||||
* @param int $ttl
|
||||
* @return array|bool
|
||||
*/
|
||||
function apc_store($key, $var = NULL, $ttl = 0)
|
||||
{
|
||||
if (is_array($key))
|
||||
{
|
||||
$aResult = array();
|
||||
foreach($key as $sKey => $value)
|
||||
{
|
||||
$aResult[] = apc_emul_store_unit($sKey, $value, $ttl);
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
return apc_emul_store_unit($key, $var, $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sKey
|
||||
* @param $value
|
||||
* @param int $iTTL time to live
|
||||
* @return bool
|
||||
*/
|
||||
function apc_emul_store_unit($sKey, $value, $iTTL)
|
||||
{
|
||||
if ($iTTL > 0)
|
||||
{
|
||||
// hint for ttl management
|
||||
$sKey = '-'.$sKey;
|
||||
}
|
||||
|
||||
$sFilename = apc_emul_get_cache_filename($sKey);
|
||||
// try to create the folder
|
||||
$sDirname = dirname($sFilename);
|
||||
if (!file_exists($sDirname))
|
||||
{
|
||||
if (!@mkdir($sDirname, 0755, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$bRes = !(@file_put_contents($sFilename, serialize($value), LOCK_EX) === false);
|
||||
apc_emul_manage_new_entry($sFilename);
|
||||
return $bRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key string|array
|
||||
* @return mixed
|
||||
*/
|
||||
function apc_fetch($key)
|
||||
{
|
||||
if (is_array($key))
|
||||
{
|
||||
$aResult = array();
|
||||
foreach($key as $sKey)
|
||||
{
|
||||
$aResult[$sKey] = apc_emul_fetch_unit($sKey);
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
return apc_emul_fetch_unit($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sKey
|
||||
* @return bool|mixed
|
||||
*/
|
||||
function apc_emul_fetch_unit($sKey)
|
||||
{
|
||||
// Try the 'TTLed' version
|
||||
$sValue = apc_emul_readcache_locked(apc_emul_get_cache_filename('-'.$sKey));
|
||||
if ($sValue === false)
|
||||
{
|
||||
$sValue = apc_emul_readcache_locked(apc_emul_get_cache_filename($sKey));
|
||||
if ($sValue === false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$oRes = @unserialize($sValue);
|
||||
return $oRes;
|
||||
}
|
||||
|
||||
function apc_emul_readcache_locked($sFilename)
|
||||
{
|
||||
$file = @fopen($sFilename, 'r');
|
||||
if ($file === false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
flock($file, LOCK_SH);
|
||||
$sContent = @fread($file, @filesize($sFilename));
|
||||
flock($file, LOCK_UN);
|
||||
fclose($file);
|
||||
return $sContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $cache_type
|
||||
* @return bool
|
||||
*/
|
||||
function apc_clear_cache($cache_type = '')
|
||||
{
|
||||
$sRootCacheDir = apc_emul_get_cache_filename('');
|
||||
apc_emul_delete_entry($sRootCacheDir);
|
||||
return true;
|
||||
}
|
||||
|
||||
function apc_emul_delete_entry($sCache)
|
||||
{
|
||||
if (is_dir($sCache))
|
||||
{
|
||||
$aFiles = array_diff(scandir($sCache), array('.', '..'));
|
||||
foreach($aFiles as $sFile)
|
||||
{
|
||||
$sSubFile = $sCache.'/'.$sFile;
|
||||
if (!apc_emul_delete_entry($sSubFile))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!@rmdir($sCache))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!@unlink($sCache))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return bool|string[]
|
||||
*/
|
||||
function apc_delete($key)
|
||||
{
|
||||
return apc_emul_delete_entry(apc_emul_get_cache_filename($key));
|
||||
}
|
||||
|
||||
|
||||
function apc_emul_get_cache_filename($sKey)
|
||||
{
|
||||
$sPath = str_replace(array(' ', '/', '\\', '.'), '-', $sKey);
|
||||
return utils::GetCachePath().'apc-emul/'.$sPath;
|
||||
}
|
||||
|
||||
|
||||
/** Manage the cache files when a new cache entry is added
|
||||
* @param string $sNewFilename new cache file added
|
||||
*/
|
||||
function apc_emul_manage_new_entry($sNewFilename)
|
||||
{
|
||||
// Check only once per request
|
||||
static $aFilesByTime = null;
|
||||
static $iFileCount = 0;
|
||||
$iMaxFiles = MetaModel::GetConfig()->Get('apc_cache_emulation.max_entries');
|
||||
if ($iMaxFiles == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!$aFilesByTime)
|
||||
{
|
||||
$sRootCacheDir = apc_emul_get_cache_filename('');
|
||||
$aFilesByTime = apc_emul_list_files_time($sRootCacheDir);
|
||||
$iFileCount = count($aFilesByTime);
|
||||
if ($iMaxFiles !== 0)
|
||||
{
|
||||
asort($aFilesByTime);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aFilesByTime[$sNewFilename] = time();
|
||||
$iFileCount++;
|
||||
}
|
||||
if ($iFileCount > $iMaxFiles)
|
||||
{
|
||||
$iFileNbToRemove = $iFileCount - $iMaxFiles;
|
||||
foreach($aFilesByTime as $sFileToRemove => $iTime)
|
||||
{
|
||||
@unlink($sFileToRemove);
|
||||
if ($iFileNbToRemove-- === 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
$aFilesByTime = array_slice($aFilesByTime, $iFileCount - $iMaxFiles, null, true);
|
||||
$iFileCount = $iMaxFiles;
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the list of files with their associated access time
|
||||
* @param string $sCheck Directory to scan
|
||||
* @param array $aFilesByTime used by recursion
|
||||
* @return array
|
||||
*/
|
||||
function apc_emul_list_files_time($sCheck, &$aFilesByTime = array())
|
||||
{
|
||||
// Garbage collection
|
||||
$aFiles = array_diff(@scandir($sCheck), array('.', '..'));
|
||||
foreach($aFiles as $sFile)
|
||||
{
|
||||
$sSubFile = $sCheck.'/'.$sFile;
|
||||
if (is_dir($sSubFile))
|
||||
{
|
||||
apc_emul_list_files_time($sSubFile, $aFilesByTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iTime = apc_emul_get_file_time($sSubFile);
|
||||
if ($iTime !== false)
|
||||
{
|
||||
$aFilesByTime[$sSubFile] = $iTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aFilesByTime;
|
||||
}
|
||||
|
||||
/** Get the file access time if TTL is managed
|
||||
* @param string $sFilename
|
||||
* @return bool|int returns the file atime or false if not relevant
|
||||
*/
|
||||
function apc_emul_get_file_time($sFilename)
|
||||
{
|
||||
if (strpos(basename($sFilename), '-') === 0)
|
||||
{
|
||||
return @fileatime($sFilename);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -702,7 +702,7 @@ abstract class AttributeDefinition
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception("Unknown verb '$sVerb' for attribute ".$this->GetCode().' in class '.get_class($oHostObj));
|
||||
throw new Exception("Unknown verb '$sVerb' for attribute ".$this->GetCode().' in class '.get_class($oHostObject));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -1053,20 +1053,20 @@ class AttributeLinkedSet extends AttributeDefinition
|
||||
|
||||
$oLinkSet = clone $value; // Workaround/Safety net for Trac #887
|
||||
$iLimit = MetaModel::GetConfig()->Get('max_linkset_output');
|
||||
if ($iLimit > 0)
|
||||
$iCount = 0;
|
||||
$aNames = array();
|
||||
foreach($oLinkSet as $oItem)
|
||||
{
|
||||
$oLinkSet->SetLimit($iLimit);
|
||||
}
|
||||
$aNames = $oLinkSet->GetColumnAsArray($sRemoteName);
|
||||
if ($iLimit > 0)
|
||||
{
|
||||
$iTotal = $oLinkSet->Count();
|
||||
if ($iTotal > count($aNames))
|
||||
if (($iLimit > 0) && ($iCount == $iLimit))
|
||||
{
|
||||
$aNames[] = '... '.Dict::Format('UI:TruncatedResults', count($aNames), $iTotal);
|
||||
$iTotal = $oLinkSet->Count();
|
||||
$aNames[] = '... '.Dict::Format('UI:TruncatedResults', $iCount, $iTotal);
|
||||
break;
|
||||
}
|
||||
$aNames[] = $oItem->Get($sRemoteName);
|
||||
$iCount++;
|
||||
}
|
||||
|
||||
|
||||
switch($sVerb)
|
||||
{
|
||||
case '':
|
||||
@@ -1342,6 +1342,29 @@ class AttributeLinkedSet extends AttributeDefinition
|
||||
return $oSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $proposedValue
|
||||
* @param $oHostObj
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function MakeRealValue($proposedValue, $oHostObj){
|
||||
if($proposedValue === null)
|
||||
{
|
||||
$sLinkedClass = $this->GetLinkedClass();
|
||||
$aLinkedObjectsArray = array();
|
||||
$oSet = DBObjectSet::FromArray($sLinkedClass, $aLinkedObjectsArray);
|
||||
|
||||
return new ormLinkSet(
|
||||
get_class($oHostObj),
|
||||
$this->GetCode(),
|
||||
$oSet
|
||||
);
|
||||
}
|
||||
|
||||
return $proposedValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ormLinkSet $val1
|
||||
* @param ormLinkSet $val2
|
||||
@@ -1355,7 +1378,7 @@ class AttributeLinkedSet extends AttributeDefinition
|
||||
}
|
||||
else
|
||||
{
|
||||
$bAreEquivalent = $val1->Equals($val2);
|
||||
$bAreEquivalent = ($val2->HasDelta() === false);
|
||||
}
|
||||
return $bAreEquivalent;
|
||||
}
|
||||
@@ -3963,6 +3986,42 @@ class AttributeDateTime extends AttributeDBField
|
||||
return $oFormField;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function EnumTemplateVerbs()
|
||||
{
|
||||
return array(
|
||||
'' => 'Formatted representation',
|
||||
'raw' => 'Not formatted representation',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function GetForTemplate($value, $sVerb, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
switch ($sVerb)
|
||||
{
|
||||
case '':
|
||||
case 'text':
|
||||
return static::GetFormat()->format($value);
|
||||
break;
|
||||
case 'html':
|
||||
// Note: Not passing formatted value as the method will format it.
|
||||
return $this->GetAsHTML($value);
|
||||
break;
|
||||
case 'raw':
|
||||
return $value;
|
||||
break;
|
||||
default:
|
||||
return parent::GetForTemplate($value, $sVerb, $oHostObject, $bLocalize);
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return parent::ListExpectedParams();
|
||||
@@ -5207,75 +5266,34 @@ class AttributeBlob extends AttributeDefinition
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
// Facilitate things: allow administrators to upload a document
|
||||
// from a CSV by specifying its path/URL
|
||||
|
||||
/**
|
||||
* Users can provide the document from an URL (including an URL on iTop itself)
|
||||
* for CSV import. Administrators can even provide the path to a local file
|
||||
* {@inheritDoc}
|
||||
* @see AttributeDefinition::MakeRealValue()
|
||||
*/
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if ($proposedValue === null) return null;
|
||||
|
||||
if (is_object($proposedValue))
|
||||
{
|
||||
$proposedValue = clone $proposedValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file_exists($proposedValue) && UserRights::IsAdministrator())
|
||||
try
|
||||
{
|
||||
$sContent = file_get_contents($proposedValue);
|
||||
$sExtension = strtolower(pathinfo($proposedValue, PATHINFO_EXTENSION));
|
||||
$sMimeType = "application/x-octet-stream";
|
||||
$aKnownExtensions = array(
|
||||
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
|
||||
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
|
||||
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
|
||||
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
|
||||
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
|
||||
'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
|
||||
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12.xlsx',
|
||||
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
|
||||
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
|
||||
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
|
||||
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
|
||||
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
|
||||
'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
|
||||
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
|
||||
'jpg' => 'image/jpeg',
|
||||
'jpeg' => 'image/jpeg',
|
||||
'gif' => 'image/gif',
|
||||
'png' => 'image/png',
|
||||
'pdf' => 'application/pdf',
|
||||
'doc' => 'application/msword',
|
||||
'dot' => 'application/msword',
|
||||
'xls' => 'application/vnd.ms-excel',
|
||||
'ppt' => 'application/vnd.ms-powerpoint',
|
||||
'vsd' => 'application/x-visio',
|
||||
'vdx' => 'application/visio.drawing',
|
||||
'odt' => 'application/vnd.oasis.opendocument.text',
|
||||
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
|
||||
'odp' => 'application/vnd.oasis.opendocument.presentation',
|
||||
'zip' => 'application/zip',
|
||||
'txt' => 'text/plain',
|
||||
'htm' => 'text/html',
|
||||
'html' => 'text/html',
|
||||
'exe' => 'application/octet-stream'
|
||||
);
|
||||
|
||||
if (!array_key_exists($sExtension, $aKnownExtensions) && extension_loaded('fileinfo'))
|
||||
{
|
||||
$finfo = new finfo(FILEINFO_MIME);
|
||||
$sMimeType = $finfo->file($proposedValue);
|
||||
}
|
||||
return new ormDocument($sContent, $sMimeType);
|
||||
// Read the file from iTop, an URL (or the local file system - for admins only)
|
||||
$proposedValue = Utils::FileGetContentsAndMIMEType($proposedValue);
|
||||
}
|
||||
else
|
||||
catch(Exception $e)
|
||||
{
|
||||
return new ormDocument($proposedValue, 'text/plain');
|
||||
}
|
||||
IssueLog::Warning(get_class($this)."::MakeRealValue - ".$e->getMessage());
|
||||
// Not a real document !! store is as text !!! (This was the default behavior before)
|
||||
$proposedValue = new ormDocument($e->getMessage()." \n".$proposedValue, 'text/plain');
|
||||
}
|
||||
}
|
||||
return $proposedValue;
|
||||
}
|
||||
@@ -5390,6 +5408,11 @@ class AttributeBlob extends AttributeDefinition
|
||||
|
||||
public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true, $bConvertToPlainText = false)
|
||||
{
|
||||
$sAttCode = $this->GetCode();
|
||||
if ($sValue instanceof ormDocument && !$sValue->IsEmpty())
|
||||
{
|
||||
return $sValue->GetDownloadURL(get_class($oHostObject), $oHostObject->GetKey(), $sAttCode);
|
||||
}
|
||||
return ''; // Not exportable in CSV !
|
||||
}
|
||||
|
||||
@@ -5493,48 +5516,49 @@ class AttributeImage extends AttributeBlob
|
||||
{
|
||||
public function GetEditClass() {return "Image";}
|
||||
|
||||
// Facilitate things: allow administrators to upload a document
|
||||
// from a CSV by specifying its path/URL
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see AttributeBlob::MakeRealValue()
|
||||
*/
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_object($proposedValue))
|
||||
{
|
||||
$proposedValue = clone $proposedValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file_exists($proposedValue) && UserRights::IsAdministrator())
|
||||
{
|
||||
$sContent = file_get_contents($proposedValue);
|
||||
$sExtension = strtolower(pathinfo($proposedValue, PATHINFO_EXTENSION));
|
||||
$sMimeType = "application/x-octet-stream";
|
||||
$aKnownExtensions = array(
|
||||
'jpg' => 'image/jpeg',
|
||||
'jpeg' => 'image/jpeg',
|
||||
'gif' => 'image/gif',
|
||||
'png' => 'image/png'
|
||||
);
|
||||
|
||||
if (!array_key_exists($sExtension, $aKnownExtensions) && extension_loaded('fileinfo'))
|
||||
{
|
||||
$finfo = new finfo(FILEINFO_MIME);
|
||||
$sMimeType = $finfo->file($proposedValue);
|
||||
}
|
||||
return new ormDocument($sContent, $sMimeType);
|
||||
}
|
||||
}
|
||||
return $proposedValue;
|
||||
$oDoc = parent::MakeRealValue($proposedValue, $oHostObj);
|
||||
// The validation of the MIME Type is done by CheckFormat below
|
||||
return $oDoc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check that the supplied ormDocument actually contains an image
|
||||
* {@inheritDoc}
|
||||
* @see AttributeDefinition::CheckFormat()
|
||||
*/
|
||||
public function CheckFormat($value)
|
||||
{
|
||||
if ($value instanceof ormDocument && !$value->IsEmpty())
|
||||
{
|
||||
return ($value->GetMainMimeType() == 'image');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
$iMaxWidthPx = $this->Get('display_max_width');
|
||||
$iMaxHeightPx = $this->Get('display_max_height');
|
||||
$sUrl = $this->Get('default_image');
|
||||
$sRet = '<img src="'.$sUrl.'" style="max-width: '.$iMaxWidthPx.'px; max-height: '.$iMaxHeightPx.'px">';
|
||||
$sRet = ($sUrl !== null) ? '<img src="'.$sUrl.'" style="max-width: '.$iMaxWidthPx.'px; max-height: '.$iMaxHeightPx.'px">' : '';
|
||||
if (is_object($value) && !$value->IsEmpty())
|
||||
{
|
||||
$sUrl = $value->GetDownloadURL(get_class($oHostObject), $oHostObject->GetKey(), $this->GetCode());
|
||||
if ($oHostObject->IsNew() || ($oHostObject->IsModified() && (array_key_exists($this->GetCode(), $oHostObject->ListChanges()))))
|
||||
{
|
||||
// If the object is modified (or not yet stored in the database) we must serve the content of the image directly inline
|
||||
// otherwise (if we just give an URL) the browser will be given the wrong content... and may cache it
|
||||
$sUrl = 'data:'.$value->GetMimeType().';base64,'.base64_encode($value->GetData());
|
||||
}
|
||||
else
|
||||
{
|
||||
$sUrl = $value->GetDownloadURL(get_class($oHostObject), $oHostObject->GetKey(), $this->GetCode());
|
||||
}
|
||||
$sRet = '<img src="'.$sUrl.'" style="max-width: '.$iMaxWidthPx.'px; max-height: '.$iMaxHeightPx.'px">';
|
||||
}
|
||||
return '<div class="view-image" style="width: '.$iMaxWidthPx.'px; height: '.$iMaxHeightPx.'px;"><span class="helper-middle"></span>'.$sRet.'</div>';
|
||||
@@ -7370,7 +7394,7 @@ class AttributeCustomFields extends AttributeDefinition
|
||||
|
||||
public function GetEditValue($sValue, $oHostObj = null)
|
||||
{
|
||||
return 'GetEditValueNotImplemented for '.get_class($this);
|
||||
return $this->GetForTemplate($sValue, '', $oHostObj, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7773,3 +7797,16 @@ class AttributeObsolescenceFlag extends AttributeBoolean
|
||||
}
|
||||
}
|
||||
|
||||
class AttributeObsolescenceDate extends AttributeDate
|
||||
{
|
||||
public function GetLabel($sDefault = null)
|
||||
{
|
||||
$sDefault = Dict::S('Core:AttributeObsolescenceDate/Label', $sDefault);
|
||||
return parent::GetLabel($sDefault);
|
||||
}
|
||||
public function GetDescription($sDefault = null)
|
||||
{
|
||||
$sDefault = Dict::S('Core:AttributeObsolescenceDate/Label+', $sDefault);
|
||||
return parent::GetDescription($sDefault);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,10 +468,11 @@ class BulkChange
|
||||
//
|
||||
foreach ($this->m_aAttList as $sAttCode => $iCol)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
|
||||
// skip the private key, if any
|
||||
if ($sAttCode == 'id') continue;
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
|
||||
// skip reconciliation keys
|
||||
if (!$oAttDef->IsWritable() && in_array($sAttCode, $this->m_aReconcilKeys)){ continue; }
|
||||
|
||||
|
||||
@@ -33,13 +33,15 @@ class MySQLException extends CoreException
|
||||
{
|
||||
if ($oException != null)
|
||||
{
|
||||
$aContext['mysql_error'] = $oException->getCode();
|
||||
$aContext['mysql_errno'] = $oException->getMessage();
|
||||
$aContext['mysql_errno'] = $oException->getCode();
|
||||
$this->code = $oException->getCode();
|
||||
$aContext['mysql_error'] = $oException->getMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
$aContext['mysql_error'] = CMDBSource::GetError();
|
||||
$aContext['mysql_errno'] = CMDBSource::GetErrNo();
|
||||
$this->code = CMDBSource::GetErrNo();
|
||||
$aContext['mysql_error'] = CMDBSource::GetError();
|
||||
}
|
||||
parent::__construct($sIssue, $aContext);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
|
||||
|
||||
define('ITOP_APPLICATION', 'iTop');
|
||||
define('ITOP_VERSION', '2.4.x');
|
||||
define('ITOP_APPLICATION_SHORT', 'iTop');
|
||||
define('ITOP_VERSION', '2.4.0');
|
||||
define('ITOP_REVISION', 'svn');
|
||||
define('ITOP_BUILD_DATE', '$WCNOW$');
|
||||
|
||||
@@ -435,6 +436,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'apc_cache_emulation.max_entries' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'Maximum number of cache entries (0 means no limit)',
|
||||
'default' => 1000,
|
||||
'value' => 1000,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'timezone' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Timezone (reference: http://php.net/manual/en/timezones.php). If empty, it will be left unchanged and MUST be explicitely configured in PHP',
|
||||
@@ -953,6 +962,30 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'disable_attachments_download_legacy_portal' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Disable attachments download from legacy portal',
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'optimize_requests_for_join_count' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Optimize request joins to minimize the count (default is true, try to set it to false in case of performance issues)',
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'high_cardinality_classes' => array(
|
||||
'type' => 'array',
|
||||
'description' => 'List of classes with high cardinality (force auto-complete mode)',
|
||||
'default' => array(),
|
||||
'value' => array(),
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
);
|
||||
|
||||
public function IsProperty($sPropCode)
|
||||
|
||||
@@ -112,4 +112,13 @@ class SecurityException extends CoreException
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Throwned when querying on an object that exists in the database but is archived
|
||||
*
|
||||
* @see N.1108
|
||||
*/
|
||||
class ArchivedObjectException extends CoreException
|
||||
{
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -1731,6 +1731,14 @@ abstract class DBObject implements iDisplay
|
||||
|
||||
$this->m_bIsInDB = true;
|
||||
$this->m_bDirty = false;
|
||||
foreach ($this->m_aCurrValues as $sAttCode => $value)
|
||||
{
|
||||
if (is_object($value))
|
||||
{
|
||||
$value = clone $value;
|
||||
}
|
||||
$this->m_aOrigValues[$sAttCode] = $value;
|
||||
}
|
||||
|
||||
$this->AfterInsert();
|
||||
|
||||
@@ -2922,7 +2930,7 @@ abstract class DBObject implements iDisplay
|
||||
$oSearch->AllowAllData();
|
||||
}
|
||||
$oSet = new CMDBObjectSet($oSearch);
|
||||
if ($oSet->Count() > 0)
|
||||
if ($oSet->Count(1) > 0)
|
||||
{
|
||||
$aDependentObjects[$sRemoteClass][$sExtKeyAttCode] = array(
|
||||
'attribute' => $oExtKeyAttDef,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
// Copyright (c) 2010-2018 Combodo SARL
|
||||
//
|
||||
// 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.
|
||||
@@ -15,14 +15,7 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Define filters for a given class of objects (formerly named "filter")
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 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);
|
||||
@@ -33,7 +26,6 @@ class DBObjectSearch extends DBSearch
|
||||
private $m_aSelectedClasses; // selected for the output (alias => class name)
|
||||
private $m_oSearchCondition;
|
||||
private $m_aParams;
|
||||
private $m_aFullText;
|
||||
private $m_aPointingTo;
|
||||
private $m_aReferencedBy;
|
||||
|
||||
@@ -54,7 +46,6 @@ class DBObjectSearch extends DBSearch
|
||||
$this->m_aClasses = array($sClassAlias => $sClass);
|
||||
$this->m_oSearchCondition = new TrueExpression;
|
||||
$this->m_aParams = array();
|
||||
$this->m_aFullText = array();
|
||||
$this->m_aPointingTo = array();
|
||||
$this->m_aReferencedBy = array();
|
||||
}
|
||||
@@ -285,7 +276,6 @@ class DBObjectSearch extends DBSearch
|
||||
public function IsAny()
|
||||
{
|
||||
if (!$this->m_oSearchCondition->IsTrue()) return false;
|
||||
if (count($this->m_aFullText) > 0) return false;
|
||||
if (count($this->m_aPointingTo) > 0) return false;
|
||||
if (count($this->m_aReferencedBy) > 0) return false;
|
||||
return true;
|
||||
@@ -367,10 +357,19 @@ class DBObjectSearch extends DBSearch
|
||||
$this->AddConditionExpression($oNewCondition);
|
||||
}
|
||||
|
||||
public function AddCondition($sFilterCode, $value, $sOpCode = null, $bParseSeachString = false)
|
||||
/**
|
||||
* @param string $sFilterCode
|
||||
* @param mixed $value
|
||||
* @param string $sOpCode operator to use : 'IN', 'NOT IN', 'Contains',' Begins with', 'Finishes with', ...
|
||||
* @param bool $bParseSearchString
|
||||
*
|
||||
* @throws \CoreException
|
||||
*
|
||||
* @see AddConditionForInOperatorUsingParam for IN/NOT IN queries with lots of params
|
||||
*/
|
||||
public function AddCondition($sFilterCode, $value, $sOpCode = null, $bParseSearchString = false)
|
||||
{
|
||||
MyHelpers::CheckKeyInArray('filter code in class: '.$this->GetClass(), $sFilterCode, MetaModel::GetClassFilterDefs($this->GetClass()));
|
||||
$oFilterDef = MetaModel::GetClassFilterDef($this->GetClass(), $sFilterCode);
|
||||
|
||||
$oField = new FieldExpression($sFilterCode, $this->GetClassAlias());
|
||||
if (empty($sOpCode))
|
||||
@@ -382,15 +381,15 @@ class DBObjectSearch extends DBSearch
|
||||
else
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->GetClass(), $sFilterCode);
|
||||
$oNewCondition = $oAttDef->GetSmartConditionExpression($value, $oField, $this->m_aParams, $bParseSeachString);
|
||||
$oNewCondition = $oAttDef->GetSmartConditionExpression($value, $oField, $this->m_aParams, $bParseSearchString);
|
||||
$this->AddConditionExpression($oNewCondition);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Parse search strings if needed and if the filter code corresponds to a valid attcode
|
||||
if($bParseSeachString && MetaModel::IsValidAttCode($this->GetClass(), $sFilterCode))
|
||||
if($bParseSearchString && MetaModel::IsValidAttCode($this->GetClass(), $sFilterCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sFilterCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->GetClass(), $sFilterCode);
|
||||
$value = $oAttDef->ParseSearchString($value);
|
||||
}
|
||||
|
||||
@@ -408,14 +407,14 @@ class DBObjectSearch extends DBSearch
|
||||
throw new CoreException('Deprecated operator, please consider using OQL (SQL) expressions like "(TO_DAYS(NOW()) - TO_DAYS(x)) AS AgeDays"', array('operator' => $sOpCode));
|
||||
break;
|
||||
|
||||
case "IN":
|
||||
case 'IN':
|
||||
if (!is_array($value)) $value = array($value);
|
||||
if (count($value) === 0) throw new Exception('AddCondition '.$sOpCode.': Value cannot be an empty array.');
|
||||
$sListExpr = '('.implode(', ', CMDBSource::Quote($value)).')';
|
||||
$sOQLCondition = $oField->Render()." IN $sListExpr";
|
||||
break;
|
||||
|
||||
case "NOTIN":
|
||||
case 'NOTIN':
|
||||
if (!is_array($value)) $value = array($value);
|
||||
if (count($value) === 0) throw new Exception('AddCondition '.$sOpCode.': Value cannot be an empty array.');
|
||||
$sListExpr = '('.implode(', ', CMDBSource::Quote($value)).')';
|
||||
@@ -469,6 +468,8 @@ class DBObjectSearch extends DBSearch
|
||||
break;
|
||||
case "IN":
|
||||
case "NOTIN":
|
||||
// this will parse all of the values... Can take forever if there are lots of them !
|
||||
// In this case using a parameter is far better : WHERE ... IN (:my_param)
|
||||
$oNewCondition = Expression::FromOQL($sOQLCondition);
|
||||
break;
|
||||
|
||||
@@ -483,6 +484,44 @@ class DBObjectSearch extends DBSearch
|
||||
$this->AddConditionExpression($oNewCondition);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sFilterCode attribute code to use
|
||||
* @param array $aValues
|
||||
* @param bool $bPositiveMatch if true will add a IN filter, else a NOT IN
|
||||
*
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function AddConditionForInOperatorUsingParam($sFilterCode, $aValues, $bPositiveMatch = true)
|
||||
{
|
||||
$oFieldExpression = new FieldExpression($sFilterCode, $this->GetClassAlias());
|
||||
|
||||
$sOperator = $bPositiveMatch ? 'IN' : 'NOT IN';
|
||||
|
||||
$sInParamName = $this->GenerateUniqueParamName();
|
||||
$oParamExpression = new VariableExpression($sInParamName);
|
||||
$this->SetInternalParams(array($sInParamName => $aValues));
|
||||
|
||||
$oListExpression = new ListExpression(array($oParamExpression));
|
||||
|
||||
$oInCondition = new BinaryExpression($oFieldExpression, $sOperator, $oListExpression);
|
||||
$this->AddConditionExpression($oInCondition);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string a unique param name
|
||||
*/
|
||||
private function GenerateUniqueParamName() {
|
||||
$iExistingParamsNb = count($this->m_aParams);
|
||||
$iCurrentArrayParamNb = $iExistingParamsNb + 1;
|
||||
$sParamName = 'param'.$iCurrentArrayParamNb;
|
||||
|
||||
if (isset($this->m_aParams[$sParamName])) {
|
||||
$sParamName .= '_'.microtime(true) . '_' .rand(0,100);
|
||||
}
|
||||
|
||||
return $sParamName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a condition on external keys or link sets
|
||||
* @param sAttSpec Can be either an attribute code or extkey->[sAttSpec] or linkset->[sAttSpec] and so on, recursively
|
||||
@@ -549,9 +588,24 @@ class DBObjectSearch extends DBSearch
|
||||
}
|
||||
}
|
||||
|
||||
public function AddCondition_FullText($sFullText)
|
||||
public function AddCondition_FullText($sNeedle)
|
||||
{
|
||||
$this->m_aFullText[] = $sFullText;
|
||||
// Transform the full text condition into additional condition expression
|
||||
$aFullTextFields = array();
|
||||
foreach (MetaModel::ListAttributeDefs($this->GetClass()) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if (!$oAttDef->IsScalar()) continue;
|
||||
if ($oAttDef->IsExternalKey()) continue;
|
||||
$aFullTextFields[] = new FieldExpression($sAttCode, $this->GetClassAlias());
|
||||
}
|
||||
$oTextFields = new CharConcatWSExpression(' ', $aFullTextFields);
|
||||
|
||||
$sQueryParam = 'needle';
|
||||
$oFlexNeedle = new CharConcatExpression(array(new ScalarExpression('%'), new VariableExpression($sQueryParam), new ScalarExpression('%')));
|
||||
|
||||
$oNewCond = new BinaryExpression($oTextFields, 'LIKE', $oFlexNeedle);
|
||||
$this->AddConditionExpression($oNewCond);
|
||||
$this->m_aParams[$sQueryParam] = $sNeedle;
|
||||
}
|
||||
|
||||
protected function AddToNameSpace(&$aClassAliases, &$aAliasTranslation, $bTranslateMainAlias = true)
|
||||
@@ -973,8 +1027,6 @@ class DBObjectSearch extends DBSearch
|
||||
// Translate search condition into our aliasing scheme
|
||||
$aAliasTranslation[$oFilter->GetClassAlias()]['*'] = $this->GetClassAlias();
|
||||
|
||||
$this->m_aFullText = array_merge($this->m_aFullText, $oFilter->m_aFullText);
|
||||
|
||||
foreach($oFilter->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
|
||||
{
|
||||
foreach($aPointingTo as $iOperatorCode => $aFilter)
|
||||
@@ -1001,7 +1053,7 @@ class DBObjectSearch extends DBSearch
|
||||
}
|
||||
|
||||
public function GetCriteria() {return $this->m_oSearchCondition;}
|
||||
public function GetCriteria_FullText() {return $this->m_aFullText;}
|
||||
public function GetCriteria_FullText() {throw new Exception("Removed GetCriteria_FullText");}
|
||||
protected function GetCriteria_PointingTo($sKeyAttCode = "")
|
||||
{
|
||||
if (empty($sKeyAttCode))
|
||||
@@ -1119,11 +1171,6 @@ class DBObjectSearch extends DBSearch
|
||||
$sRes .= $this->ToOQL_Joins();
|
||||
$sRes .= " WHERE ".$this->m_oSearchCondition->Render($aParams, $bRetrofitParams);
|
||||
|
||||
// Temporary: add more info about other conditions, necessary to avoid strange behaviors with the cache
|
||||
foreach($this->m_aFullText as $sFullText)
|
||||
{
|
||||
$sRes .= " AND MATCHES '$sFullText'";
|
||||
}
|
||||
if ($bWithAllowAllFlag && $this->m_bAllowAllData)
|
||||
{
|
||||
$sRes .= " ALLOW ALL DATA";
|
||||
@@ -1468,10 +1515,32 @@ class DBObjectSearch extends DBSearch
|
||||
|
||||
// Create a unique cache id
|
||||
//
|
||||
$aContextData = array();
|
||||
$bCanCache = true;
|
||||
if (self::$m_bQueryCacheEnabled || self::$m_bTraceQueries)
|
||||
{
|
||||
if (isset($_SERVER['REQUEST_URI']))
|
||||
{
|
||||
$aContextData['sRequestUri'] = $_SERVER['REQUEST_URI'];
|
||||
}
|
||||
else if (isset($_SERVER['SCRIPT_NAME']))
|
||||
{
|
||||
$aContextData['sRequestUri'] = $_SERVER['SCRIPT_NAME'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$aContextData['sRequestUri'] = '';
|
||||
}
|
||||
|
||||
// Need to identify the query
|
||||
$sOqlQuery = $oSearch->ToOql(false, null, true);
|
||||
if ((strpos($sOqlQuery, '`id` IN (') !== false) || (strpos($sOqlQuery, '`id` NOT IN (') !== false))
|
||||
{
|
||||
// Requests containing "id IN" are not worth caching
|
||||
$bCanCache = false;
|
||||
}
|
||||
|
||||
$aContextData['sOqlQuery'] = $sOqlQuery;
|
||||
|
||||
if (count($aModifierProperties))
|
||||
{
|
||||
@@ -1482,12 +1551,14 @@ class DBObjectSearch extends DBSearch
|
||||
{
|
||||
$sModifierProperties = '';
|
||||
}
|
||||
$aContextData['sModifierProperties'] = $sModifierProperties;
|
||||
|
||||
$sRawId = $sOqlQuery.$sModifierProperties;
|
||||
if (!is_null($aAttToLoad))
|
||||
{
|
||||
$sRawId .= json_encode($aAttToLoad);
|
||||
}
|
||||
$aContextData['aAttToLoad'] = $aAttToLoad;
|
||||
if (!is_null($aGroupByExpr))
|
||||
{
|
||||
foreach($aGroupByExpr as $sAlias => $oExpr)
|
||||
@@ -1495,13 +1566,20 @@ class DBObjectSearch extends DBSearch
|
||||
$sRawId .= 'g:'.$sAlias.'!'.$oExpr->Render();
|
||||
}
|
||||
}
|
||||
$aContextData['aGroupByExpr'] = $aGroupByExpr;
|
||||
$sRawId .= $bGetCount;
|
||||
$aContextData['bGetCount'] = $bGetCount;
|
||||
if (is_array($aSelectedClasses))
|
||||
{
|
||||
$sRawId .= implode(',', $aSelectedClasses); // Unions may alter the list of selected columns
|
||||
}
|
||||
$sRawId .= $oSearch->GetArchiveMode() ? '--arch' : '';
|
||||
$sRawId .= $oSearch->GetShowObsoleteData() ? '--obso' : '';
|
||||
$aContextData['aSelectedClasses'] = $aSelectedClasses;
|
||||
$bIsArchiveMode = $oSearch->GetArchiveMode();
|
||||
$sRawId .= $bIsArchiveMode ? '--arch' : '';
|
||||
$bShowObsoleteData = $oSearch->GetShowObsoleteData();
|
||||
$sRawId .= $bShowObsoleteData ? '--obso' : '';
|
||||
$aContextData['bIsArchiveMode'] = $bIsArchiveMode;
|
||||
$aContextData['bShowObsoleteData'] = $bShowObsoleteData;
|
||||
$sOqlId = md5($sRawId);
|
||||
}
|
||||
else
|
||||
@@ -1557,8 +1635,9 @@ class DBObjectSearch extends DBSearch
|
||||
|
||||
if (self::$m_bQueryCacheEnabled)
|
||||
{
|
||||
if (self::$m_bUseAPCCache)
|
||||
if ($bCanCache && self::$m_bUseAPCCache)
|
||||
{
|
||||
$oSQLQuery->m_aContextData = $aContextData;
|
||||
$oKPI = new ExecutionKPI();
|
||||
apc_store($sOqlAPCCacheId, $oSQLQuery, self::$m_iQueryCacheTTL);
|
||||
$oKPI->ComputeStats('Query APC (store)', $sOqlQuery);
|
||||
@@ -1570,6 +1649,14 @@ class DBObjectSearch extends DBSearch
|
||||
return $oSQLQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aAttToLoad
|
||||
* @param $bGetCount
|
||||
* @param $aModifierProperties
|
||||
* @param null $aGroupByExpr
|
||||
* @param null $aSelectedClasses
|
||||
* @return null|SQLObjectQuery
|
||||
*/
|
||||
protected function BuildSQLQueryStruct($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr = null, $aSelectedClasses = null)
|
||||
{
|
||||
$oBuild = new QueryBuilderContext($this, $aModifierProperties, $aGroupByExpr, $aSelectedClasses);
|
||||
@@ -1614,6 +1701,12 @@ class DBObjectSearch extends DBSearch
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $oBuild
|
||||
* @param null $aAttToLoad
|
||||
* @param array $aValues
|
||||
* @return null|SQLObjectQuery
|
||||
*/
|
||||
protected function MakeSQLObjectQuery(&$oBuild, $aAttToLoad = null, $aValues = array())
|
||||
{
|
||||
// Note: query class might be different than the class of the filter
|
||||
@@ -1623,9 +1716,9 @@ class DBObjectSearch extends DBSearch
|
||||
|
||||
$bIsOnQueriedClass = array_key_exists($sClassAlias, $oBuild->GetRootFilter()->GetSelectedClasses());
|
||||
|
||||
self::DbgTrace("Entering: ".$this->ToOQL().", ".($bIsOnQueriedClass ? "MAIN" : "SECONDARY"));
|
||||
//self::DbgTrace("Entering: ".$this->ToOQL().", ".($bIsOnQueriedClass ? "MAIN" : "SECONDARY"));
|
||||
|
||||
$sRootClass = MetaModel::GetRootClass($sClass);
|
||||
//$sRootClass = MetaModel::GetRootClass($sClass);
|
||||
$sKeyField = MetaModel::DBGetKey($sClass);
|
||||
|
||||
if ($bIsOnQueriedClass)
|
||||
@@ -1658,30 +1751,10 @@ class DBObjectSearch extends DBSearch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Transform the full text condition into additional condition expression
|
||||
$aFullText = $this->GetCriteria_FullText();
|
||||
if (count($aFullText) > 0)
|
||||
{
|
||||
$aFullTextFields = array();
|
||||
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if (!$oAttDef->IsScalar()) continue;
|
||||
if ($oAttDef->IsExternalKey()) continue;
|
||||
$aFullTextFields[] = new FieldExpression($sAttCode, $sClassAlias);
|
||||
}
|
||||
$oTextFields = new CharConcatWSExpression(' ', $aFullTextFields);
|
||||
|
||||
foreach($aFullText as $sFTNeedle)
|
||||
{
|
||||
$oNewCond = new BinaryExpression($oTextFields, 'LIKE', new ScalarExpression("%$sFTNeedle%"));
|
||||
$oBuild->m_oQBExpressions->AddCondition($oNewCond);
|
||||
}
|
||||
}
|
||||
}
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n";
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n";
|
||||
$aExpectedAtts = array(); // array of (attcode => fieldexpression)
|
||||
//echo "<p>".__LINE__.": GetUnresolvedFields($sClassAlias, ...)</p>\n";
|
||||
//echo "<p>".__LINE__.": GetUnresolvedFields($sClassAlias, ...)</p>\n";
|
||||
$oBuild->m_oQBExpressions->GetUnresolvedFields($sClassAlias, $aExpectedAtts);
|
||||
|
||||
// Compute a clear view of required joins (from the current class)
|
||||
@@ -1798,37 +1871,86 @@ class DBObjectSearch extends DBSearch
|
||||
}
|
||||
}
|
||||
|
||||
// First query built upon on the leaf (ie current) class
|
||||
//
|
||||
self::DbgTrace("Main (=leaf) class, call MakeSQLObjectQuerySingleTable()");
|
||||
if (MetaModel::HasTable($sClass))
|
||||
$bRootFirst = MetaModel::GetConfig()->Get('optimize_requests_for_join_count');
|
||||
if ($bRootFirst)
|
||||
{
|
||||
$oSelectBase = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sClass, $aExtKeys, $aValues);
|
||||
// First query built from the root, adding all tables including the leaf
|
||||
// Before N.1065 we were joining from the leaf first, but this wasn't a good choice :
|
||||
// most of the time (obsolescence, friendlyname, ...) we want to get a root attribute !
|
||||
//
|
||||
$oSelectBase = null;
|
||||
$aClassHierarchy = MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL, true);
|
||||
$bIsClassStandaloneClass = (count($aClassHierarchy) == 1);
|
||||
foreach($aClassHierarchy as $sSomeClass)
|
||||
{
|
||||
if (!MetaModel::HasTable($sSomeClass))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
self::DbgTrace("Adding join from root to leaf: $sSomeClass... let's call MakeSQLObjectQuerySingleTable()");
|
||||
$oSelectParentTable = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sSomeClass, $aExtKeys, $aValues);
|
||||
if (is_null($oSelectBase))
|
||||
{
|
||||
$oSelectBase = $oSelectParentTable;
|
||||
if (!$bIsClassStandaloneClass && (MetaModel::IsRootClass($sSomeClass)))
|
||||
{
|
||||
// As we're linking to root class first, we're adding a where clause on the finalClass attribute :
|
||||
// COALESCE($sRootClassFinalClass IN ('$sExpectedClasses'), 1)
|
||||
// If we don't, the child classes can be removed in the query optimisation phase, including the leaf that was queried
|
||||
// So we still need to filter records to only those corresponding to the child classes !
|
||||
// The coalesce is mandatory if we have a polymorphic query (left join)
|
||||
$oClassListExpr = ListExpression::FromScalars(MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL));
|
||||
$sFinalClassSqlColumnName = MetaModel::DBGetClassField($sSomeClass);
|
||||
$oClassExpr = new FieldExpression($sFinalClassSqlColumnName, $oSelectBase->GetTableAlias());
|
||||
$oInExpression = new BinaryExpression($oClassExpr, 'IN', $oClassListExpr);
|
||||
$oTrueExpression = new TrueExpression();
|
||||
$aCoalesceAttr = array($oInExpression, $oTrueExpression);
|
||||
$oFinalClassRestriction = new FunctionExpression("COALESCE", $aCoalesceAttr);
|
||||
|
||||
$oBuild->m_oQBExpressions->AddCondition($oFinalClassRestriction);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSelectBase->AddInnerJoin($oSelectParentTable, $sKeyField, MetaModel::DBGetKey($sSomeClass));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSelectBase = null;
|
||||
|
||||
// As the join will not filter on the expected classes, we have to specify it explicitely
|
||||
$sExpectedClasses = implode("', '", MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL));
|
||||
$oFinalClassRestriction = Expression::FromOQL("`$sClassAlias`.finalclass IN ('$sExpectedClasses')");
|
||||
$oBuild->m_oQBExpressions->AddCondition($oFinalClassRestriction);
|
||||
}
|
||||
|
||||
// Then we join the queries of the eventual parent classes (compound model)
|
||||
foreach(MetaModel::EnumParentClasses($sClass) as $sParentClass)
|
||||
{
|
||||
if (!MetaModel::HasTable($sParentClass)) continue;
|
||||
|
||||
self::DbgTrace("Parent class: $sParentClass... let's call MakeSQLObjectQuerySingleTable()");
|
||||
$oSelectParentTable = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sParentClass, $aExtKeys, $aValues);
|
||||
if (is_null($oSelectBase))
|
||||
// First query built upon on the leaf (ie current) class
|
||||
//
|
||||
self::DbgTrace("Main (=leaf) class, call MakeSQLObjectQuerySingleTable()");
|
||||
if (MetaModel::HasTable($sClass))
|
||||
{
|
||||
$oSelectBase = $oSelectParentTable;
|
||||
$oSelectBase = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sClass, $aExtKeys, $aValues);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSelectBase->AddInnerJoin($oSelectParentTable, $sKeyField, MetaModel::DBGetKey($sParentClass));
|
||||
$oSelectBase = null;
|
||||
|
||||
// As the join will not filter on the expected classes, we have to specify it explicitely
|
||||
$sExpectedClasses = implode("', '", MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL));
|
||||
$oFinalClassRestriction = Expression::FromOQL("`$sClassAlias`.finalclass IN ('$sExpectedClasses')");
|
||||
$oBuild->m_oQBExpressions->AddCondition($oFinalClassRestriction);
|
||||
}
|
||||
|
||||
// Then we join the queries of the eventual parent classes (compound model)
|
||||
foreach(MetaModel::EnumParentClasses($sClass) as $sParentClass)
|
||||
{
|
||||
if (!MetaModel::HasTable($sParentClass)) continue;
|
||||
|
||||
self::DbgTrace("Parent class: $sParentClass... let's call MakeSQLObjectQuerySingleTable()");
|
||||
$oSelectParentTable = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sParentClass, $aExtKeys, $aValues);
|
||||
if (is_null($oSelectBase))
|
||||
{
|
||||
$oSelectBase = $oSelectParentTable;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSelectBase->AddInnerJoin($oSelectParentTable, $sKeyField, MetaModel::DBGetKey($sParentClass));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2159,8 +2281,14 @@ class DBObjectSearch extends DBSearch
|
||||
* Get the expression for the class and its subclasses (if finalclass = 'subclass' ...)
|
||||
* Simplifies the final expression by grouping classes having the same expression
|
||||
*/
|
||||
static protected function GetPolymorphicExpression($sClass, $sAttCode)
|
||||
static public function GetPolymorphicExpression($sClass, $sAttCode)
|
||||
{
|
||||
$oExpression = ExpressionCache::GetCachedExpression($sClass, $sAttCode);
|
||||
if (!empty($oExpression))
|
||||
{
|
||||
return $oExpression;
|
||||
}
|
||||
|
||||
// 1st step - get all of the required expressions (instantiable classes)
|
||||
// and group them using their OQL representation
|
||||
//
|
||||
|
||||
@@ -69,7 +69,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
* @var int
|
||||
*/
|
||||
protected $m_iCurrRow;
|
||||
/*
|
||||
/**
|
||||
* @var DBSearch
|
||||
*/
|
||||
protected $m_oFilter;
|
||||
@@ -77,18 +77,20 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
* @var mysqli_result
|
||||
*/
|
||||
protected $m_oSQLResult;
|
||||
protected $m_bSort;
|
||||
|
||||
/**
|
||||
* Create a new set based on a Search definition.
|
||||
*
|
||||
*
|
||||
* @param DBSearch $oFilter The search filter defining the objects which are part of the set (multiple columns/objects per row are supported)
|
||||
* @param hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending
|
||||
* @param hash $aArgs Values to substitute for the search/query parameters (if any). Format: param_name => value
|
||||
* @param array $aOrderBy Array of '[<classalias>.]attcode' => bAscending
|
||||
* @param array $aArgs Values to substitute for the search/query parameters (if any). Format: param_name => value
|
||||
* @param hash $aExtendedDataSpec
|
||||
* @param int $iLimitCount Maximum number of rows to load (i.e. equivalent to MySQL's LIMIT start, count)
|
||||
* @param int $iLimitStart Index of the first row to load (i.e. equivalent to MySQL's LIMIT start, count)
|
||||
* @param bool $bSort if false no order by is done
|
||||
*/
|
||||
public function __construct(DBSearch $oFilter, $aOrderBy = array(), $aArgs = array(), $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0)
|
||||
public function __construct(DBSearch $oFilter, $aOrderBy = array(), $aArgs = array(), $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0, $bSort = true)
|
||||
{
|
||||
$this->m_oFilter = $oFilter->DeepClone();
|
||||
$this->m_aAddedIds = array();
|
||||
@@ -98,6 +100,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
$this->m_aExtendedDataSpec = $aExtendedDataSpec;
|
||||
$this->m_iLimitCount = $iLimitCount;
|
||||
$this->m_iLimitStart = $iLimitStart;
|
||||
$this->m_bSort = $bSort;
|
||||
|
||||
$this->m_iNumTotalDBRows = null;
|
||||
$this->m_iNumLoadedDBRows = 0;
|
||||
@@ -195,11 +198,25 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad);
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad] = $oAttDef;
|
||||
if ($oAttDef->IsExternalKey())
|
||||
if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
|
||||
{
|
||||
// Add the external key friendly name anytime
|
||||
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_friendlyname');
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_friendlyname'] = $oFriendlyNameAttDef;
|
||||
|
||||
if (MetaModel::IsArchivable($oAttDef->GetTargetClass(EXTKEY_ABSOLUTE)))
|
||||
{
|
||||
// Add the archive flag if necessary
|
||||
$oArchiveFlagAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_archive_flag');
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_archive_flag'] = $oArchiveFlagAttDef;
|
||||
}
|
||||
|
||||
if (MetaModel::IsObsoletable($oAttDef->GetTargetClass(EXTKEY_ABSOLUTE)))
|
||||
{
|
||||
// Add the obsolescence flag if necessary
|
||||
$oObsoleteFlagAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_obsolescence_flag');
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_obsolescence_flag'] = $oObsoleteFlagAttDef;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -207,6 +224,20 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, 'friendlyname');
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['friendlyname'] = $oFriendlyNameAttDef;
|
||||
|
||||
if (MetaModel::IsArchivable($sClass))
|
||||
{
|
||||
// Add the archive flag if necessary
|
||||
$oArchiveFlagAttDef = MetaModel::GetAttributeDef($sClass, 'archive_flag');
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['archive_flag'] = $oArchiveFlagAttDef;
|
||||
}
|
||||
|
||||
if (MetaModel::IsObsoletable($sClass))
|
||||
{
|
||||
// Add the obsolescence flag if necessary
|
||||
$oObsoleteFlagAttDef = MetaModel::GetAttributeDef($sClass, 'obsolescence_flag');
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['obsolescence_flag'] = $oObsoleteFlagAttDef;
|
||||
}
|
||||
|
||||
// Make sure that the final class is requested anytime, whatever the specification (needed for object construction!)
|
||||
if (!MetaModel::IsStandaloneClass($sClass) && !array_key_exists('finalclass', $aAttToLoadWithAttDef[$sClassAlias]))
|
||||
{
|
||||
@@ -312,7 +343,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: After calling this method, the set cursor will be at the end of the set. You might to rewind it.
|
||||
* Note: After calling this method, the set cursor will be at the end of the set. You might want to rewind it.
|
||||
*
|
||||
* @param bool $bWithId
|
||||
* @return array
|
||||
@@ -386,7 +417,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: After calling this method, the set cursor will be at the end of the set. You might to rewind it.
|
||||
* Note: After calling this method, the set cursor will be at the end of the set. You might want to rewind it.
|
||||
*
|
||||
* @param string $sAttCode
|
||||
* @param bool $bWithId
|
||||
@@ -573,10 +604,15 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
*
|
||||
* Limitation: the sort order has no effect on objects added in-memory
|
||||
*
|
||||
* @return hash Format: field_code => boolean (true = ascending, false = descending)
|
||||
* @return array Format: field_code => boolean (true = ascending, false = descending)
|
||||
*/
|
||||
public function GetRealSortOrder()
|
||||
{
|
||||
if (!$this->m_bSort)
|
||||
{
|
||||
// No order by
|
||||
return array();
|
||||
}
|
||||
// Get the class default sort order if not specified with the API
|
||||
//
|
||||
if (empty($this->m_aOrderBy))
|
||||
@@ -598,14 +634,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
// Note: it is mandatory to set this value now, to protect against reentrance
|
||||
$this->m_bLoaded = true;
|
||||
|
||||
if ($this->m_iLimitCount > 0)
|
||||
{
|
||||
$sSQL = $this->m_oFilter->MakeSelectQuery($this->GetRealSortOrder(), $this->m_aArgs, $this->m_aAttToLoad, $this->m_aExtendedDataSpec, $this->m_iLimitCount, $this->m_iLimitStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSQL = $this->m_oFilter->MakeSelectQuery($this->GetRealSortOrder(), $this->m_aArgs, $this->m_aAttToLoad, $this->m_aExtendedDataSpec);
|
||||
}
|
||||
$sSQL = $this->_makeSelectQuery($this->m_aAttToLoad);
|
||||
|
||||
if (is_object($this->m_oSQLResult))
|
||||
{
|
||||
@@ -614,8 +643,36 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
$this->m_oSQLResult = null;
|
||||
}
|
||||
$this->m_iNumTotalDBRows = null;
|
||||
|
||||
$this->m_oSQLResult = CMDBSource::Query($sSQL);
|
||||
|
||||
try
|
||||
{
|
||||
$this->m_oSQLResult = CMDBSource::Query($sSQL);
|
||||
} catch (MySQLException $e)
|
||||
{
|
||||
// 1116 = ER_TOO_MANY_TABLES
|
||||
// https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html#error_er_too_many_tables
|
||||
if ($e->getCode() != 1116)
|
||||
{
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// N.689 Workaround for the 61 max joins in MySQL : full lazy load !
|
||||
$aAttToLoad = array();
|
||||
foreach($this->m_oFilter->GetSelectedClasses() as $sClassAlias => $sClass)
|
||||
{
|
||||
$aAttToLoad[$sClassAlias] = array();
|
||||
$bIsAbstractClass = MetaModel::IsAbstract($sClass);
|
||||
$bIsClassWithChildren = MetaModel::HasChildrenClasses($sClass);
|
||||
if ($bIsAbstractClass || $bIsClassWithChildren)
|
||||
{
|
||||
// we need finalClass field at least to be able to instantiate the real corresponding object !
|
||||
$aAttToLoad[$sClassAlias]['finalclass'] = MetaModel::GetAttributeDef($sClass, 'finalclass');
|
||||
}
|
||||
}
|
||||
$sSQL = $this->_makeSelectQuery($aAttToLoad);
|
||||
$this->m_oSQLResult = CMDBSource::Query($sSQL); // may fail again
|
||||
}
|
||||
|
||||
if ($this->m_oSQLResult === false) return;
|
||||
|
||||
if (($this->m_iLimitCount == 0) && ($this->m_iLimitStart == 0))
|
||||
@@ -626,24 +683,54 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of rows in this set. Independently of the SetLimit used for loading the set and taking into account the rows added in-memory.
|
||||
*
|
||||
* May actually perform the SQL query SELECT COUNT... if the set was not previously loaded, or loaded with a SetLimit
|
||||
*
|
||||
* @return int The total number of rows for this set.
|
||||
* @param string[] $aAttToLoad
|
||||
*
|
||||
* @return string SQL query
|
||||
*/
|
||||
public function Count()
|
||||
private function _makeSelectQuery($aAttToLoad)
|
||||
{
|
||||
if ($this->m_iLimitCount > 0)
|
||||
{
|
||||
$sSQL = $this->m_oFilter->MakeSelectQuery($this->GetRealSortOrder(), $this->m_aArgs, $aAttToLoad,
|
||||
$this->m_aExtendedDataSpec, $this->m_iLimitCount, $this->m_iLimitStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSQL = $this->m_oFilter->MakeSelectQuery($this->GetRealSortOrder(), $this->m_aArgs, $aAttToLoad,
|
||||
$this->m_aExtendedDataSpec);
|
||||
}
|
||||
|
||||
return $sSQL;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of rows in this set. Independently of the SetLimit used for loading the set and taking into
|
||||
* account the rows added in-memory.
|
||||
*
|
||||
* May actually perform the SQL query SELECT COUNT... if the set was not previously loaded, or loaded with a
|
||||
* SetLimit
|
||||
*
|
||||
* @param int $iLimit used for autocomplete: the count is only used to know if the number of entries exceed
|
||||
* a certain amount or not
|
||||
*
|
||||
* @return int The total number of rows for this set.
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function Count($iLimit = 0)
|
||||
{
|
||||
if (is_null($this->m_iNumTotalDBRows))
|
||||
{
|
||||
$sSQL = $this->m_oFilter->MakeSelectQuery(array(), $this->m_aArgs, null, null, 0, 0, true);
|
||||
$sSQL = $this->m_oFilter->MakeSelectQuery(array(), $this->m_aArgs, null, null, $iLimit, 0, true);
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
if (!$resQuery) return 0;
|
||||
|
||||
|
||||
$aRow = CMDBSource::FetchArray($resQuery);
|
||||
CMDBSource::FreeResult($resQuery);
|
||||
$this->m_iNumTotalDBRows = $aRow['COUNT'];
|
||||
}
|
||||
|
||||
return $this->m_iNumTotalDBRows + count($this->m_aAddedObjects); // Does it fix Trac #887 ??
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -474,7 +474,7 @@ class DBUnionSearch extends DBSearch
|
||||
throw new Exception('MakeUpdateQuery is not implemented for the unions!');
|
||||
}
|
||||
|
||||
protected function GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr = null, $aSelectedClasses = null)
|
||||
public function GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr = null, $aSelectedClasses = null)
|
||||
{
|
||||
if (count($this->aSearches) == 1)
|
||||
{
|
||||
@@ -496,19 +496,30 @@ class DBUnionSearch extends DBSearch
|
||||
$aSearchSelectedClasses[$sSearchAlias] = $this->aSelectedClasses[$sAlias];
|
||||
}
|
||||
|
||||
if (is_null($aAttToLoad))
|
||||
if ($bGetCount)
|
||||
{
|
||||
$aQueryAttToLoad = null;
|
||||
// Select only ids for the count to allow optimization of joins
|
||||
foreach($aSearchAliases as $sSearchAlias)
|
||||
{
|
||||
$aQueryAttToLoad[$sSearchAlias] = array();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// (Eventually) Transform the aliases
|
||||
$aQueryAttToLoad = array();
|
||||
foreach ($aAttToLoad as $sAlias => $aAttributes)
|
||||
if (is_null($aAttToLoad))
|
||||
{
|
||||
$iColumn = array_search($sAlias, $aAliases);
|
||||
$sQueryAlias = ($iColumn === false) ? $sAlias : $aSearchAliases[$iColumn];
|
||||
$aQueryAttToLoad[$sQueryAlias] = $aAttributes;
|
||||
$aQueryAttToLoad = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// (Eventually) Transform the aliases
|
||||
$aQueryAttToLoad = array();
|
||||
foreach($aAttToLoad as $sAlias => $aAttributes)
|
||||
{
|
||||
$iColumn = array_search($sAlias, $aAliases);
|
||||
$sQueryAlias = ($iColumn === false) ? $sAlias : $aSearchAliases[$iColumn];
|
||||
$aQueryAttToLoad[$sQueryAlias] = $aAttributes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -408,4 +408,30 @@ class EventLoginUsage extends Event
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
class EventOnObject extends Event
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_event_onobject",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("obj_class", array("allowed_values"=>null, "sql"=>"obj_class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("obj_key", array("allowed_values"=>null, "sql"=>"obj_key", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'obj_class', 'obj_key', 'message')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'obj_class', 'obj_key', 'message')); // Attributes to be displayed for a list
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,10 +188,10 @@ EOF
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
$sRet = $oAttDef->GetAsCSV($value, '', '', $oObj);
|
||||
}
|
||||
else if ($value instanceOf ormCustomFieldsValue)
|
||||
else if ($value instanceOf ormDocument)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
$sRet = $oAttDef->GetAsCSV($value, "\n", '', $oObj);
|
||||
$sRet = $oAttDef->GetAsCSV($value, '', '', $oObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
110
core/expressioncache.class.inc.php
Normal file
110
core/expressioncache.class.inc.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
// Copyright (c) 2010-2017 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/>
|
||||
//
|
||||
|
||||
class ExpressionCache
|
||||
{
|
||||
static private $aCache = array();
|
||||
|
||||
static public function GetCachedExpression($sClass, $sAttCode)
|
||||
{
|
||||
// read current cache
|
||||
@include_once (static::GetCacheFileName());
|
||||
|
||||
$oExpr = null;
|
||||
$sKey = static::GetKey($sClass, $sAttCode);
|
||||
if (array_key_exists($sKey, static::$aCache))
|
||||
{
|
||||
$oExpr = static::$aCache[$sKey];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (class_exists('ExpressionCacheData'))
|
||||
{
|
||||
if (array_key_exists($sKey, ExpressionCacheData::$aCache))
|
||||
{
|
||||
$sVal = ExpressionCacheData::$aCache[$sKey];
|
||||
$oExpr = unserialize($sVal);
|
||||
static::$aCache[$sKey] = $oExpr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $oExpr;
|
||||
}
|
||||
|
||||
|
||||
static public function Warmup()
|
||||
{
|
||||
$sFilePath = static::GetCacheFileName();
|
||||
|
||||
if (!is_file($sFilePath))
|
||||
{
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
// Copyright (c) 2010-2017 Combodo SARL
|
||||
// Generated Expression Cache file
|
||||
|
||||
class ExpressionCacheData
|
||||
{
|
||||
static \$aCache = array(
|
||||
EOF;
|
||||
|
||||
foreach(MetaModel::GetClasses() as $sClass)
|
||||
{
|
||||
$content .= static::GetSerializedExpression($sClass, 'friendlyname');
|
||||
if (MetaModel::IsObsoletable($sClass))
|
||||
{
|
||||
$content .= static::GetSerializedExpression($sClass, 'obsolescence_flag');
|
||||
}
|
||||
}
|
||||
|
||||
$content .= <<<EOF
|
||||
);
|
||||
}
|
||||
EOF;
|
||||
|
||||
file_put_contents($sFilePath, $content);
|
||||
}
|
||||
}
|
||||
|
||||
static private function GetSerializedExpression($sClass, $sAttCode)
|
||||
{
|
||||
$sKey = static::GetKey($sClass, $sAttCode);
|
||||
$oExpr = DBObjectSearch::GetPolymorphicExpression($sClass, $sAttCode);
|
||||
return "'".$sKey."' => '".serialize($oExpr)."',\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sClass
|
||||
* @param $sAttCode
|
||||
* @return string
|
||||
*/
|
||||
static private function GetKey($sClass, $sAttCode)
|
||||
{
|
||||
return $sClass.'::'.$sAttCode;
|
||||
}
|
||||
|
||||
public static function GetCacheFileName()
|
||||
{
|
||||
return utils::GetCachePath().'expressioncache.php';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -156,6 +156,7 @@ class HTMLDOMSanitizer extends HTMLSanitizer
|
||||
'body' => array(),
|
||||
'a' => array('href', 'name', 'style', 'target', 'title'),
|
||||
'p' => array('style'),
|
||||
'blockquote' => array('style'),
|
||||
'br' => array(),
|
||||
'span' => array('style'),
|
||||
'div' => array('style'),
|
||||
@@ -212,9 +213,17 @@ class HTMLDOMSanitizer extends HTMLSanitizer
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
// Building href validation pattern from url and email validation patterns as the patterns are not used the same way in HTML content than in standard attributes value.
|
||||
// eg. "foo@bar.com" vs "mailto:foo@bar.com?subject=Title&body=Hello%20world"
|
||||
if (!array_key_exists('href', self::$aAttrsWhiteList))
|
||||
{
|
||||
$sPattern = '/'.str_replace('/', '\/', utils::GetConfig()->Get('url_validation_pattern')).'/i';
|
||||
// Regular urls
|
||||
$sUrlPattern = utils::GetConfig()->Get('url_validation_pattern');
|
||||
// Mailto urls
|
||||
$sMailtoPattern = '(mailto:(' . utils::GetConfig()->Get('email_validation_pattern') . ')(?:\?(?:subject|body)=([a-zA-Z0-9+\$_.-]*)(?:&(?:subject|body)=([a-zA-Z0-9+\$_.-]*))?)?)';
|
||||
|
||||
$sPattern = $sUrlPattern . '|' . $sMailtoPattern;
|
||||
$sPattern = '/'.str_replace('/', '\/', $sPattern).'/i';
|
||||
self::$aAttrsWhiteList['href'] = $sPattern;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
// Copyright (c) 2010-2017 Combodo SARL
|
||||
//
|
||||
// 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.
|
||||
@@ -15,6 +15,7 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
require_once(APPROOT.'core/modulehandler.class.inc.php');
|
||||
require_once(APPROOT.'core/querybuildercontext.class.inc.php');
|
||||
@@ -23,6 +24,7 @@ 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');
|
||||
require_once(APPROOT.'core/expressioncache.class.inc.php');
|
||||
|
||||
/**
|
||||
* Metamodel
|
||||
@@ -331,9 +333,16 @@ abstract class MetaModel
|
||||
}
|
||||
final static public function GetObsolescenceExpression($sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
$sOql = self::$m_aClassParams[$sClass]['obsolescence_expression'];
|
||||
$oRet = Expression::FromOQL("COALESCE($sOql, 0)");
|
||||
if (self::IsObsoletable($sClass))
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
$sOql = self::$m_aClassParams[$sClass]['obsolescence_expression'];
|
||||
$oRet = Expression::FromOQL("COALESCE($sOql, 0)");
|
||||
}
|
||||
else
|
||||
{
|
||||
$oRet = Expression::FromOQL("0");
|
||||
}
|
||||
return $oRet;
|
||||
}
|
||||
final static public function GetNameSpec($sClass)
|
||||
@@ -413,13 +422,13 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the friendly name IIF it is equivalent to a single attribute
|
||||
*/
|
||||
* Returns the friendly name IIF it is equivalent to a single attribute
|
||||
*/
|
||||
final static public function GetFriendlyNameAttributeCode($sClass)
|
||||
{
|
||||
$aNameSpec = self::GetNameSpec($sClass);
|
||||
$sFormat = trim($aNameSpec[0]);
|
||||
$aAttributes = $aNameSpec[1];
|
||||
$aAttributes = $aNameSpec[1];
|
||||
if (($sFormat != '') && ($sFormat != '%1$s'))
|
||||
{
|
||||
return null;
|
||||
@@ -431,6 +440,20 @@ abstract class MetaModel
|
||||
return reset($aAttributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of attributes composing the friendlyname
|
||||
*
|
||||
* @param $sClass
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
final static public function GetFriendlyNameAttributeCodeList($sClass)
|
||||
{
|
||||
$aNameSpec = self::GetNameSpec($sClass);
|
||||
$aAttributes = $aNameSpec[1];
|
||||
return $aAttributes;
|
||||
}
|
||||
|
||||
final static public function GetStateAttributeCode($sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
@@ -1082,11 +1105,37 @@ abstract class MetaModel
|
||||
return $aClassRelations;
|
||||
}
|
||||
|
||||
final static public function GetRelationDescription($sRelCode)
|
||||
/**
|
||||
* @param string $sRelCode Relation code
|
||||
* @param bool $bDown Relation direction, is it downstream (true) or upstream (false). Default is true.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
final static public function GetRelationDescription($sRelCode, $bDown = true)
|
||||
{
|
||||
return Dict::S("Relation:$sRelCode/Description");
|
||||
// Legacy convention had only one description describing the relation.
|
||||
// Now, as the relation is bidirectional, we have a description for each directions.
|
||||
$sLegacy = Dict::S("Relation:$sRelCode/Description");
|
||||
|
||||
if($bDown)
|
||||
{
|
||||
$sKey = "Relation:$sRelCode/DownStream+";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sKey = "Relation:$sRelCode/UpStream+";
|
||||
}
|
||||
$sRet = Dict::S($sKey, $sLegacy);
|
||||
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sRelCode Relation code
|
||||
* @param bool $bDown Relation direction, is it downstream (true) or upstream (false). Default is true.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
final static public function GetRelationLabel($sRelCode, $bDown = true)
|
||||
{
|
||||
if ($bDown)
|
||||
@@ -1857,15 +1906,13 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare external fields and filters
|
||||
// Add final class to external keys
|
||||
//
|
||||
// Add magic attributes to the classes
|
||||
foreach (self::GetClasses() as $sClass)
|
||||
{
|
||||
$sRootClass = self::$m_aRootClasses[$sClass];
|
||||
|
||||
// Create the friendly name attribute
|
||||
$sFriendlyNameAttCode = 'friendlyname';
|
||||
$sFriendlyNameAttCode = 'friendlyname';
|
||||
$oFriendlyName = new AttributeFriendlyName($sFriendlyNameAttCode);
|
||||
self::AddMagicAttribute($oFriendlyName, $sClass);
|
||||
|
||||
@@ -1875,7 +1922,7 @@ abstract class MetaModel
|
||||
$oArchiveFlag = new AttributeArchiveFlag('archive_flag');
|
||||
self::AddMagicAttribute($oArchiveFlag, $sClass);
|
||||
|
||||
$oArchiveDate = new AttributeDate('archive_date', array('magic' => true, "allowed_values"=>null, "sql"=>'archive_date', "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array()));
|
||||
$oArchiveDate = new AttributeArchiveDate('archive_date', array('magic' => true, "allowed_values" => null, "sql" => 'archive_date', "default_value" => '', "is_null_allowed" => true, "depends_on" => array()));
|
||||
self::AddMagicAttribute($oArchiveDate, $sClass);
|
||||
}
|
||||
elseif (self::$m_aClassParams[$sClass]["archive"])
|
||||
@@ -1898,7 +1945,7 @@ abstract class MetaModel
|
||||
|
||||
if (self::$m_aRootClasses[$sClass] == $sClass)
|
||||
{
|
||||
$oObsolescenceDate = new AttributeDate('obsolescence_date', array('magic' => true, "allowed_values" => null, "sql" => 'obsolescence_date', "default_value" => '', "is_null_allowed" => true, "depends_on" => array()));
|
||||
$oObsolescenceDate = new AttributeObsolescenceDate('obsolescence_date', array('magic' => true, "allowed_values" => null, "sql" => 'obsolescence_date', "default_value" => '', "is_null_allowed" => true, "depends_on" => array()));
|
||||
self::AddMagicAttribute($oObsolescenceDate, $sClass);
|
||||
}
|
||||
else
|
||||
@@ -1909,6 +1956,13 @@ abstract class MetaModel
|
||||
self::$m_aAttribOrigins[$sClass]['obsolescence_date'] = $sRootClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare external fields and filters
|
||||
// Add final class to external keys
|
||||
// Add magic attributes to external keys (finalclass, friendlyname, archive_flag, obsolescence_flag)
|
||||
foreach (self::GetClasses() as $sClass)
|
||||
{
|
||||
foreach (self::$m_aAttribDefs[$sClass] as $sAttCode => $oAttDef)
|
||||
{
|
||||
// Compute the filter codes
|
||||
@@ -3766,6 +3820,7 @@ abstract class MetaModel
|
||||
//
|
||||
$aTableInfo = CMDBSource::GetTableInfo($sTable);
|
||||
$aTableInfo['Fields'][$sKeyField]['used'] = true;
|
||||
$aFriendlynameAttcodes = self::GetFriendlyNameAttributeCodeList($sClass);
|
||||
foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
if (!$oAttDef->CopyOnAllTables())
|
||||
@@ -3779,6 +3834,14 @@ abstract class MetaModel
|
||||
$aTableInfo['Fields'][$sField]['used'] = true;
|
||||
|
||||
$bIndexNeeded = $oAttDef->RequiresIndex();
|
||||
if (!$bIndexNeeded)
|
||||
{
|
||||
// Add an index on the columns of the friendlyname
|
||||
if (in_array($sField, $aFriendlynameAttcodes))
|
||||
{
|
||||
$bIndexNeeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
$sFieldDefinition = "`$sField` $sDBFieldSpec";
|
||||
if (!CMDBSource::IsField($sTable, $sField))
|
||||
@@ -3787,6 +3850,7 @@ abstract class MetaModel
|
||||
$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` ADD $sFieldDefinition";
|
||||
if ($bIndexNeeded)
|
||||
{
|
||||
$aTableInfo['Indexes'][$sField]['used'] = true;
|
||||
$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` ADD INDEX (`$sField`)";
|
||||
}
|
||||
if (array_key_exists($sTable, $aCreateTable))
|
||||
@@ -3794,6 +3858,7 @@ abstract class MetaModel
|
||||
$aCreateTableItems[$sTable][$sField] = $sFieldDefinition;
|
||||
if ($bIndexNeeded)
|
||||
{
|
||||
$aTableInfo['Indexes'][$sField]['used'] = true;
|
||||
$aCreateTableItems[$sTable][] = "INDEX (`$sField`)";
|
||||
}
|
||||
}
|
||||
@@ -3802,6 +3867,7 @@ abstract class MetaModel
|
||||
$aAlterTableItems[$sTable][$sField] = "ADD $sFieldDefinition";
|
||||
if ($bIndexNeeded)
|
||||
{
|
||||
$aTableInfo['Indexes'][$sField]['used'] = true;
|
||||
$aAlterTableItems[$sTable][] = "ADD INDEX (`$sField`)";
|
||||
}
|
||||
}
|
||||
@@ -3827,6 +3893,7 @@ abstract class MetaModel
|
||||
//
|
||||
if ($bIndexNeeded && !CMDBSource::HasIndex($sTable, $sField, array($sField)))
|
||||
{
|
||||
$aTableInfo['Indexes'][$sField]['used'] = true;
|
||||
$aErrors[$sClass][$sAttCode][] = "Foreign key '$sField' in table '$sTable' should have an index";
|
||||
if (CMDBSource::HasIndex($sTable, $sField))
|
||||
{
|
||||
@@ -3848,7 +3915,10 @@ abstract class MetaModel
|
||||
foreach (self::DBGetIndexes($sClass) as $aColumns)
|
||||
{
|
||||
$sIndexId = implode('_', $aColumns);
|
||||
|
||||
if (isset($aTableInfo['Indexes'][$sIndexId]['used']) && $aTableInfo['Indexes'][$sIndexId]['used'])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(!CMDBSource::HasIndex($sTable, $sIndexId, $aColumns))
|
||||
{
|
||||
$sColumns = "`".implode("`, `", $aColumns)."`";
|
||||
@@ -4394,6 +4464,8 @@ abstract class MetaModel
|
||||
echo "Debug<br/>\n";
|
||||
self::static_var_dump();
|
||||
}
|
||||
|
||||
ExpressionCache::Warmup();
|
||||
}
|
||||
|
||||
public static function LoadConfig($oConfiguration, $bAllowCache = false)
|
||||
@@ -4590,6 +4662,14 @@ abstract class MetaModel
|
||||
return self::$m_oConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string The environment in which the model has been loaded (e.g. 'production')
|
||||
*/
|
||||
public static function GetEnvironment()
|
||||
{
|
||||
return self::$m_sEnvironment;
|
||||
}
|
||||
|
||||
public static function GetEnvironmentId()
|
||||
{
|
||||
return md5(APPROOT).'-'.self::$m_sEnvironment;
|
||||
@@ -4675,6 +4755,18 @@ abstract class MetaModel
|
||||
return $iTotalHits.' ('.implode(', ', $aRes).')';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param int $iKey
|
||||
* @param bool $bMustBeFound
|
||||
* @param bool $bAllowAllData if true then no rights filtering
|
||||
* @param array $aModifierProperties
|
||||
*
|
||||
* @return string[] column name / value array
|
||||
* @throws CoreException if no result found and $bMustBeFound=true
|
||||
*
|
||||
* @see utils::PushArchiveMode() to enable search on archived objects
|
||||
*/
|
||||
public static function MakeSingleRow($sClass, $iKey, $bMustBeFound = true, $bAllowAllData = false, $aModifierProperties = null)
|
||||
{
|
||||
// Build the query cache signature
|
||||
@@ -4731,13 +4823,27 @@ abstract class MetaModel
|
||||
|
||||
$aRow = CMDBSource::FetchArray($res);
|
||||
CMDBSource::FreeResult($res);
|
||||
|
||||
if ($bMustBeFound && empty($aRow))
|
||||
{
|
||||
throw new CoreException("No result for the single row query: '$sSQL'");
|
||||
}
|
||||
|
||||
return $aRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a column name / value array to a {@link DBObject}
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param string[] $aRow column name / value array
|
||||
* @param string $sClassAlias
|
||||
* @param string[] $aAttToLoad
|
||||
* @param array $aExtendedDataSpec
|
||||
*
|
||||
* @return DBObject
|
||||
* @throws CoreException if finalClass cannot be found
|
||||
*/
|
||||
public static function GetObjectByRow($sClass, $aRow, $sClassAlias = '', $aAttToLoad = null, $aExtendedDataSpec = null)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
@@ -4771,30 +4877,75 @@ abstract class MetaModel
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sClass
|
||||
* Search for the specified class and id.
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param $iKey
|
||||
* @param bool $bMustBeFound
|
||||
* @param bool $bAllowAllData
|
||||
* @param null $aModifierProperties
|
||||
* @return DBObject|null
|
||||
* @return DBObject|null null if : (the object is not found) or (archive mode disabled and object is archived and $bMustBeFound=false)
|
||||
* @throws CoreException if no result found and $bMustBeFound=true
|
||||
* @throws ArchivedObjectException if archive mode disabled and result is archived and $bMustBeFound=true
|
||||
*
|
||||
* @see MetaModel::GetObjectWithArchive to get object even if it's archived
|
||||
* @see utils::PushArchiveMode() to enable search on archived objects
|
||||
*/
|
||||
public static function GetObject($sClass, $iKey, $bMustBeFound = true, $bAllowAllData = false, $aModifierProperties = null)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
$oObject = self::GetObjectWithArchive($sClass, $iKey, $bMustBeFound, $bAllowAllData, $aModifierProperties);
|
||||
|
||||
if (empty($oObject))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!utils::IsArchiveMode() && $oObject->IsArchived())
|
||||
{
|
||||
if ($bMustBeFound)
|
||||
{
|
||||
throw new ArchivedObjectException("The object $sClass::$iKey is archived");
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return $oObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the specified class and id. If the object is archived it will be returned anyway (this is for pre-2.4
|
||||
* module compatibility, see N.1108)
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param int $iKey
|
||||
* @param bool $bMustBeFound
|
||||
* @param bool $bAllowAllData
|
||||
* @param array $aModifierProperties
|
||||
*
|
||||
* @return DBObject|null
|
||||
* @throws CoreException if no result found and $bMustBeFound=true
|
||||
*
|
||||
* @since 2.4 introduction of the archive functionalities
|
||||
*
|
||||
* @see MetaModel::GetObject() same but returns null or ArchivedObjectFoundException if object exists but is archived
|
||||
*/
|
||||
public static function GetObjectWithArchive($sClass, $iKey, $bMustBeFound = true, $bAllowAllData = false, $aModifierProperties = null)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
|
||||
utils::PushArchiveMode(true);
|
||||
$aRow = self::MakeSingleRow($sClass, $iKey, $bMustBeFound, $bAllowAllData, $aModifierProperties);
|
||||
utils::PopArchiveMode();
|
||||
|
||||
if (empty($aRow))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return self::GetObjectByRow($sClass, $aRow);
|
||||
}
|
||||
|
||||
public static function GetObjectWithArchive($sClass, $iKey, $bMustBeFound = true, $bAllowAllData = false, $aModifierProperties = null)
|
||||
{
|
||||
utils::PushArchiveMode(true);
|
||||
$oObject = static::GetObject($sClass, $iKey, $bMustBeFound, $bAllowAllData, $aModifierProperties);
|
||||
utils::PopArchiveMode();
|
||||
return $oObject;
|
||||
return self::GetObjectByRow($sClass, $aRow); // null should not be returned, this is handled in the callee
|
||||
}
|
||||
|
||||
public static function GetObjectByName($sClass, $sName, $bMustBeFound = true)
|
||||
@@ -5226,21 +5377,12 @@ abstract class MetaModel
|
||||
|
||||
public static function GetCacheEntries($sEnvironment = null)
|
||||
{
|
||||
if (!function_exists('apc_cache_info')) return array();
|
||||
if (is_null($sEnvironment))
|
||||
{
|
||||
$sEnvironment = MetaModel::GetEnvironmentId();
|
||||
}
|
||||
$aEntries = array();
|
||||
if (extension_loaded('apcu'))
|
||||
{
|
||||
// Beware: APCu behaves slightly differently from APC !!
|
||||
$aCacheUserData = @apc_cache_info();
|
||||
}
|
||||
else
|
||||
{
|
||||
$aCacheUserData = @apc_cache_info('user');
|
||||
}
|
||||
$aCacheUserData = apc_cache_info_compat();
|
||||
if (is_array($aCacheUserData) && isset($aCacheUserData['cache_list']))
|
||||
{
|
||||
$sPrefix = 'itop-'.$sEnvironment.'-';
|
||||
|
||||
@@ -45,7 +45,7 @@ class iTopMutex
|
||||
}
|
||||
$sDBName = $oConfig->GetDBName();
|
||||
$sDBSubname = $oConfig->GetDBSubname();
|
||||
$this->sName = 'itop.'.$sName;
|
||||
$this->sName = $sName;
|
||||
if (substr($sName, -strlen($sDBName.$sDBSubname)) != $sDBName.$sDBSubname)
|
||||
{
|
||||
// If the name supplied already ends with the expected suffix
|
||||
@@ -54,6 +54,9 @@ class iTopMutex
|
||||
$this->sName .= $sDBName.$sDBSubname;
|
||||
}
|
||||
|
||||
// Limit the length of the name for MySQL > 5.7.5
|
||||
$this->sName = 'itop.'.md5($this->sName);
|
||||
|
||||
$this->bLocked = false; // Not yet locked
|
||||
|
||||
if (!array_key_exists($this->sName, self::$aAcquiredLocks))
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
// Copyright (c) 2010-2017 Combodo SARL
|
||||
//
|
||||
// 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.
|
||||
@@ -15,14 +15,7 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* General definition of an expression tree (could be OQL, SQL or whatever)
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
//
|
||||
|
||||
class MissingQueryArgument extends CoreException
|
||||
{
|
||||
@@ -89,9 +82,15 @@ abstract class Expression
|
||||
*/
|
||||
static public function FromOQL($sConditionExpr)
|
||||
{
|
||||
static $aCache = array();
|
||||
if (array_key_exists($sConditionExpr, $aCache))
|
||||
{
|
||||
return unserialize($aCache[$sConditionExpr]);
|
||||
}
|
||||
$oOql = new OqlInterpreter($sConditionExpr);
|
||||
$oExpression = $oOql->ParseExpression();
|
||||
|
||||
$aCache[$sConditionExpr] = serialize($oExpression);
|
||||
|
||||
return $oExpression;
|
||||
}
|
||||
|
||||
@@ -227,6 +226,10 @@ class BinaryExpression extends Expression
|
||||
{
|
||||
throw new CoreException('Expecting an Expression object on the right hand', array('found_class' => get_class($oRightExpr)));
|
||||
}
|
||||
if ( (($sOperator == "IN") || ($sOperator == "NOT IN")) && !$oRightExpr instanceof ListExpression)
|
||||
{
|
||||
throw new CoreException("Expecting a List Expression object on the right hand for operator $sOperator", array('found_class' => get_class($oRightExpr)));
|
||||
}
|
||||
$this->m_oLeftExpr = $oLeftExpr;
|
||||
$this->m_oRightExpr = $oRightExpr;
|
||||
$this->m_sOperator = $sOperator;
|
||||
|
||||
@@ -191,8 +191,15 @@ class ormCaseLog {
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->m_sLog;
|
||||
if($this->IsEmpty()) return '';
|
||||
|
||||
return $this->m_sLog;
|
||||
}
|
||||
|
||||
public function IsEmpty()
|
||||
{
|
||||
return ($this->m_sLog === null);
|
||||
}
|
||||
|
||||
public function ClearModifiedFlag()
|
||||
{
|
||||
|
||||
@@ -51,6 +51,8 @@ class ormDocument
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
if($this->IsEmpty()) return '';
|
||||
|
||||
return MyHelpers::beautifulstr($this->m_data, 100, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
* Object from the original set, minus the removed objects
|
||||
* @var DBObject[] array of iObjectId => DBObject
|
||||
*/
|
||||
protected $aPreserved;
|
||||
protected $aPreserved = array();
|
||||
|
||||
/**
|
||||
* @var DBObject[] New items
|
||||
@@ -74,6 +74,14 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
*/
|
||||
protected $iCursor = 0;
|
||||
|
||||
/**
|
||||
* __toString magical function overload.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* ormLinkSet constructor.
|
||||
* @param $sHostClass
|
||||
@@ -123,19 +131,18 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
{
|
||||
assert($oLink instanceof $this->sClass);
|
||||
// No impact on the iteration algorithm
|
||||
$this->aAdded[] = $oLink;
|
||||
$iObjectId = $oLink->GetKey();
|
||||
$this->aAdded[$iObjectId] = $oLink;
|
||||
$this->bHasDelta = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DBObject $oObject
|
||||
* @param string $sClassAlias
|
||||
* @deprecated
|
||||
* @deprecated Since iTop 2.4, use ormLinkset->AddItem() instead.
|
||||
*/
|
||||
public function AddObject(DBObject $oObject, $sClassAlias = '')
|
||||
{
|
||||
trigger_error('iTop: ormLinkSet::AddObject() is deprecated use ormLinkSet::AddItem() instead.', E_USER_DEPRECATED);
|
||||
|
||||
$this->AddItem($oObject);
|
||||
}
|
||||
|
||||
@@ -150,6 +157,13 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
$this->aRemoved[$iObjectId] = $iObjectId;
|
||||
$this->bHasDelta = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (array_key_exists($iObjectId, $this->aAdded))
|
||||
{
|
||||
unset($this->aAdded[$iObjectId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,9 +172,14 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
public function ModifyItem(DBObject $oLink)
|
||||
{
|
||||
assert($oLink instanceof $this->sClass);
|
||||
|
||||
$iObjectId = $oLink->GetKey();
|
||||
$this->aModified[$iObjectId] = $oLink;
|
||||
$this->bHasDelta = true;
|
||||
if (array_key_exists($iObjectId, $this->aPreserved))
|
||||
{
|
||||
unset($this->aPreserved[$iObjectId]);
|
||||
$this->aModified[$iObjectId] = $oLink;
|
||||
$this->bHasDelta = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected function LoadOriginalIds()
|
||||
@@ -169,15 +188,22 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
{
|
||||
if ($this->oOriginalSet)
|
||||
{
|
||||
$this->aOriginalObjects = $this->oOriginalSet->ToArray();
|
||||
$this->aOriginalObjects = $this->GetArrayOfIndex();
|
||||
$this->aPreserved = $this->aOriginalObjects; // Copy (not effective until aPreserved gets modified)
|
||||
foreach ($this->aRemoved as $iObjectId)
|
||||
{
|
||||
if (array_key_exists($iObjectId, $this->aPreserved))
|
||||
{
|
||||
unset($this->aPreserved[$iObjectId]);
|
||||
}
|
||||
}
|
||||
foreach ($this->aRemoved as $iObjectId)
|
||||
{
|
||||
if (array_key_exists($iObjectId, $this->aPreserved))
|
||||
{
|
||||
unset($this->aPreserved[$iObjectId]);
|
||||
}
|
||||
}
|
||||
foreach ($this->aModified as $iObjectId => $oLink)
|
||||
{
|
||||
if (array_key_exists($iObjectId, $this->aPreserved))
|
||||
{
|
||||
unset($this->aPreserved[$iObjectId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -189,17 +215,29 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: After calling this method, the set cursor will be at the end of the set. You might want to rewind it.
|
||||
* @return array
|
||||
*/
|
||||
protected function GetArrayOfIndex()
|
||||
{
|
||||
$aRet = array();
|
||||
$this->oOriginalSet->Rewind();
|
||||
$iRow = 0;
|
||||
while ($oObject = $this->oOriginalSet->Fetch())
|
||||
{
|
||||
$aRet[$oObject->GetKey()] = $iRow++;
|
||||
}
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: After calling this method, the set cursor will be at the end of the set. You might to rewind it.
|
||||
*
|
||||
* @param bool $bWithId
|
||||
* @return array
|
||||
* @deprecated
|
||||
* @deprecated Since iTop 2.4, use foreach($this as $oItem){} instead
|
||||
*/
|
||||
public function ToArray($bWithId = true)
|
||||
{
|
||||
trigger_error('iTop: ormLinkSet::ToArray() is deprecated use foreach instead.', E_USER_DEPRECATED);
|
||||
|
||||
$aRet = array();
|
||||
foreach($this as $oItem)
|
||||
{
|
||||
@@ -215,6 +253,28 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sAttCode
|
||||
* @param bool $bWithId
|
||||
* @return array
|
||||
*/
|
||||
public function GetColumnAsArray($sAttCode, $bWithId = true)
|
||||
{
|
||||
$aRet = array();
|
||||
foreach($this as $oItem)
|
||||
{
|
||||
if ($bWithId)
|
||||
{
|
||||
$aRet[$oItem->GetKey()] = $oItem->Get($sAttCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRet[] = $oItem->Get($sAttCode);
|
||||
}
|
||||
}
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* The class of the objects of the collection (at least a common ancestor)
|
||||
*
|
||||
@@ -233,7 +293,7 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
public function Count()
|
||||
{
|
||||
$this->LoadOriginalIds();
|
||||
$iRet = count($this->aPreserved) + count($this->aAdded);
|
||||
$iRet = count($this->aPreserved) + count($this->aAdded) + count($this->aModified);
|
||||
return $iRet;
|
||||
}
|
||||
|
||||
@@ -290,11 +350,21 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
$iPreservedCount = count($this->aPreserved);
|
||||
if ($this->iCursor < $iPreservedCount)
|
||||
{
|
||||
$oRet = current($this->aPreserved);
|
||||
$iRet = current($this->aPreserved);
|
||||
$this->oOriginalSet->Seek($iRet);
|
||||
$oRet = $this->oOriginalSet->Fetch();
|
||||
}
|
||||
else
|
||||
{
|
||||
$oRet = current($this->aAdded);
|
||||
$iModifiedCount = count($this->aModified);
|
||||
if($this->iCursor < $iPreservedCount + $iModifiedCount)
|
||||
{
|
||||
$oRet = current($this->aModified);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oRet = current($this->aAdded);
|
||||
}
|
||||
}
|
||||
return $oRet;
|
||||
}
|
||||
@@ -315,9 +385,17 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
}
|
||||
else
|
||||
{
|
||||
next($this->aAdded);
|
||||
$iModifiedCount = count($this->aModified);
|
||||
if($this->iCursor < $iPreservedCount + $iModifiedCount)
|
||||
{
|
||||
next($this->aModified);
|
||||
}
|
||||
else
|
||||
{
|
||||
next($this->aAdded);
|
||||
}
|
||||
}
|
||||
// Increment AFTER moving the internal cursors because when starting aAdded, we must leave it intact
|
||||
// Increment AFTER moving the internal cursors because when starting aModified / aAdded, we must leave it intact
|
||||
$this->iCursor++;
|
||||
}
|
||||
|
||||
@@ -353,11 +431,12 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
$this->LoadOriginalIds();
|
||||
$this->LoadOriginalIds();
|
||||
|
||||
$this->iCursor = 0;
|
||||
$this->iCursor = 0;
|
||||
reset($this->aPreserved);
|
||||
reset($this->aAdded);
|
||||
reset($this->aAdded);
|
||||
reset($this->aModified);
|
||||
}
|
||||
|
||||
public function HasDelta()
|
||||
@@ -429,7 +508,7 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
$this->aAdded = array();
|
||||
$this->aRemoved = array();
|
||||
$this->aModified = array();
|
||||
$this->aPreserved = $this->aOriginalObjects;
|
||||
$this->aPreserved = ($this->aOriginalObjects === null) ? array() : $this->aOriginalObjects;
|
||||
$this->bHasDelta = false;
|
||||
|
||||
/** @var AttributeLinkedSet $oAttDef */
|
||||
@@ -504,12 +583,15 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
|
||||
// Check for the existing links
|
||||
//
|
||||
/** @var DBObject[] $aExistingLinks */
|
||||
$aExistingLinks = array();
|
||||
/** @var Int[] $aExistingRemote */
|
||||
$aExistingRemote = array();
|
||||
if (count($aCheckLinks) > 0)
|
||||
{
|
||||
$oSearch = new DBObjectSearch($this->sClass);
|
||||
$oSearch->AddCondition('id', $aCheckLinks, 'IN');
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
/** @var DBObject[] $aExistingLinks */
|
||||
$aExistingLinks = $oSet->ToArray();
|
||||
}
|
||||
|
||||
@@ -521,8 +603,7 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
$oSearch->AddCondition($sExtKeyToMe, $oHostObject->GetKey(), '=');
|
||||
$oSearch->AddCondition($sExtKeyToRemote, $aCheckRemote, 'IN');
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
/** @var Int[] $aExistingRemote */
|
||||
$aExistingRemote = $oSet->GetColumnAsArray($sExtKeyToRemote);
|
||||
$aExistingRemote = $oSet->GetColumnAsArray($sExtKeyToRemote, true);
|
||||
}
|
||||
|
||||
// Write the links according to the existing links
|
||||
@@ -536,11 +617,28 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
{
|
||||
if (count($aCheckRemote) > 0)
|
||||
{
|
||||
if (in_array($oLink->Get($sExtKeyToRemote), $aExistingRemote))
|
||||
{
|
||||
// Do not create a duplicate
|
||||
continue;
|
||||
}
|
||||
$bIsDuplicate = false;
|
||||
foreach($aExistingRemote as $sLinkKey => $sExtKey)
|
||||
{
|
||||
if ($sExtKey == $oLink->Get($sExtKeyToRemote))
|
||||
{
|
||||
// Do not create a duplicate
|
||||
// + In the case of a remove action followed by an add action
|
||||
// of an existing link,
|
||||
// the final state to consider is add action,
|
||||
// so suppress the entry in the removed list.
|
||||
if (array_key_exists($sLinkKey, $this->aRemoved))
|
||||
{
|
||||
unset($this->aRemoved[$sLinkKey]);
|
||||
}
|
||||
$bIsDuplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($bIsDuplicate)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -598,4 +696,34 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
//
|
||||
$oMtx->Unlock();
|
||||
}
|
||||
|
||||
public function ToDBObjectSet($bShowObsolete = true)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->sHostClass, $this->sAttCode);
|
||||
$oLinkSearch = $this->GetFilter();
|
||||
if ($oAttDef->IsIndirect())
|
||||
{
|
||||
$sExtKeyToRemote = $oAttDef->GetExtKeyToRemote();
|
||||
$oLinkingAttDef = MetaModel::GetAttributeDef($this->sClass, $sExtKeyToRemote);
|
||||
$sTargetClass = $oLinkingAttDef->GetTargetClass();
|
||||
if (!$bShowObsolete && MetaModel::IsObsoletable($sTargetClass))
|
||||
{
|
||||
$oNotObsolete = new BinaryExpression(
|
||||
new FieldExpression('obsolescence_flag', $sTargetClass),
|
||||
'=',
|
||||
new ScalarExpression(0)
|
||||
);
|
||||
$oNotObsoleteRemote = new DBObjectSearch($sTargetClass);
|
||||
$oNotObsoleteRemote->AddConditionExpression($oNotObsolete);
|
||||
$oLinkSearch->AddCondition_PointingTo($oNotObsoleteRemote, $sExtKeyToRemote);
|
||||
}
|
||||
}
|
||||
$oLinkSet = new DBObjectSet($oLinkSearch);
|
||||
$oLinkSet->SetShowObsoleteData($bShowObsolete);
|
||||
if ($this->HasDelta())
|
||||
{
|
||||
$oLinkSet->AddObjectArray($this->aAdded);
|
||||
}
|
||||
return $oLinkSet;
|
||||
}
|
||||
}
|
||||
@@ -226,9 +226,9 @@ EOF
|
||||
$iNewWidth = $iWidth * $fScale;
|
||||
$iNewHeight = $iHeight * $fScale;
|
||||
|
||||
$sUrl = 'data:' . $value->GetMimeType() . ';base64,' . base64_encode($value->GetData());
|
||||
$sUrl = 'data:'.$value->GetMimeType().';base64,'.base64_encode($value->GetData());
|
||||
}
|
||||
$sRet = '<img src="' . $sUrl . '" style="width: ' . $iNewWidth . 'px; height: ' . $iNewHeight . 'px">';
|
||||
$sRet = ($sUrl !== null) ? '<img src="'.$sUrl.'" style="width: '.$iNewWidth.'px; height: '.$iNewHeight.'px">' : '';
|
||||
$sRet = '<div class="view-image">'.$sRet.'</div>';
|
||||
}
|
||||
else
|
||||
|
||||
@@ -175,7 +175,8 @@ EOF
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeCustomFields)
|
||||
{
|
||||
$sRet = $oObj->GetAsHTML($sAttCode);
|
||||
// Stick to the weird implementation made in GetNextChunk
|
||||
$sRet = utils::TextToHtml($oObj->GetEditValue($sAttCode));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -326,6 +327,12 @@ EOF
|
||||
}
|
||||
$sData .= "<td x:str>$sField</td>";
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeCustomFields)
|
||||
{
|
||||
// GetAsHTML returns a table that would not fit
|
||||
$sField = utils::TextToHtml($oObj->GetEditValue($sAttCode));
|
||||
$sData .= "<td x:str>$sField</td>";
|
||||
}
|
||||
else if($oAttDef instanceof AttributeString)
|
||||
{
|
||||
$sField = $oObj->GetAsHTML($sAttCode, $this->bLocalizeOutput);
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
|
||||
class SQLObjectQuery extends SQLQuery
|
||||
{
|
||||
private $m_SourceOQL = '';
|
||||
public $m_aContextData = null;
|
||||
public $m_iOriginalTableCount = 0;
|
||||
private $m_sTable = '';
|
||||
private $m_sTableAlias = '';
|
||||
private $m_aFields = array();
|
||||
@@ -46,7 +47,7 @@ class SQLObjectQuery extends SQLQuery
|
||||
private $m_aValues = array(); // Values to set in case of an update query
|
||||
private $m_oSelectedIdField = null;
|
||||
private $m_aJoinSelects = array();
|
||||
private $m_bBeautifulQuery = false;
|
||||
protected $m_bBeautifulQuery = false;
|
||||
|
||||
// Data set by PrepareRendering()
|
||||
private $__aFrom;
|
||||
@@ -311,6 +312,14 @@ class SQLObjectQuery extends SQLQuery
|
||||
$this->PrepareRendering();
|
||||
$sFrom = self::ClauseFrom($this->__aFrom, $sIndent);
|
||||
$sWhere = self::ClauseWhere($this->m_oConditionExpr, $aArgs);
|
||||
if ($iLimitCount > 0)
|
||||
{
|
||||
$sLimit = 'LIMIT '.$iLimitStart.', '.$iLimitCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLimit = '';
|
||||
}
|
||||
if ($bGetCount)
|
||||
{
|
||||
if (count($this->__aSelectedIdFields) > 0)
|
||||
@@ -321,11 +330,13 @@ class SQLObjectQuery extends SQLQuery
|
||||
$aCountFields[] = "COALESCE($sFieldExpr, 0)"; // Null values are excluded from the count
|
||||
}
|
||||
$sCountFields = implode(', ', $aCountFields);
|
||||
$sSQL = "SELECT$sLineSep COUNT(DISTINCT $sCountFields) AS COUNT$sLineSep FROM $sFrom$sLineSep WHERE $sWhere";
|
||||
// Count can be limited for performance reason, in this case the total amount is not important,
|
||||
// we only need to know if the number of entries is greater than a certain amount.
|
||||
$sSQL = "SELECT COUNT(*) AS COUNT FROM (SELECT$sLineSep DISTINCT $sCountFields $sLineSep FROM $sFrom$sLineSep WHERE $sWhere $sLimit) AS _tatooine_";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSQL = "SELECT$sLineSep COUNT(*) AS COUNT$sLineSep FROM $sFrom$sLineSep WHERE $sWhere";
|
||||
$sSQL = "SELECT COUNT(*) AS COUNT FROM (SELECT$sLineSep 1 $sLineSep FROM $sFrom$sLineSep WHERE $sWhere $sLimit) AS _tatooine_";
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -336,14 +347,7 @@ class SQLObjectQuery extends SQLQuery
|
||||
{
|
||||
$sOrderBy = "ORDER BY $sOrderBy$sLineSep";
|
||||
}
|
||||
if ($iLimitCount > 0)
|
||||
{
|
||||
$sLimit = 'LIMIT '.$iLimitStart.', '.$iLimitCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLimit = '';
|
||||
}
|
||||
|
||||
$sSQL = "SELECT$sLineSep DISTINCT $sSelect$sLineSep FROM $sFrom$sLineSep WHERE $sWhere$sLineSep $sOrderBy $sLimit";
|
||||
}
|
||||
return $sSQL;
|
||||
@@ -510,6 +514,7 @@ class SQLObjectQuery extends SQLQuery
|
||||
|
||||
public function OptimizeJoins($aUsedTables, $bTopCall = true)
|
||||
{
|
||||
$this->m_iOriginalTableCount = $this->CountTables();
|
||||
if ($bTopCall)
|
||||
{
|
||||
// Top call: complete the list of tables absolutely required to perform the right query
|
||||
@@ -545,7 +550,7 @@ class SQLObjectQuery extends SQLQuery
|
||||
return $iRet;
|
||||
}
|
||||
|
||||
protected function CollectUsedTables(&$aTables)
|
||||
public function CollectUsedTables(&$aTables)
|
||||
{
|
||||
$this->m_oConditionExpr->CollectUsedParents($aTables);
|
||||
foreach($this->m_aFields as $sFieldAlias => $oField)
|
||||
@@ -612,4 +617,5 @@ class SQLObjectQuery extends SQLQuery
|
||||
// None of the tables is in the list of required tables
|
||||
return $bResult;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ require_once('cmdbsource.class.inc.php');
|
||||
abstract class SQLQuery
|
||||
{
|
||||
private $m_SourceOQL = '';
|
||||
private $m_bBeautifulQuery = false;
|
||||
protected $m_bBeautifulQuery = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
@@ -58,7 +58,7 @@ class SQLUnionQuery extends SQLQuery
|
||||
{
|
||||
$aQueriesHtml[] = '<p>'.$oSQLQuery->DisplayHtml().'</p>';
|
||||
}
|
||||
echo implode('UNION', $aQueries);
|
||||
echo implode('UNION', $aQueriesHtml);
|
||||
}
|
||||
|
||||
public function AddInnerJoin($oSQLQuery, $sLeftField, $sRightField, $sRightTable = '')
|
||||
@@ -85,7 +85,6 @@ class SQLUnionQuery extends SQLQuery
|
||||
{
|
||||
$this->m_bBeautifulQuery = $bBeautifulQuery;
|
||||
$sLineSep = $this->m_bBeautifulQuery ? "\n" : '';
|
||||
$sIndent = $this->m_bBeautifulQuery ? " " : null;
|
||||
|
||||
$aSelects = array();
|
||||
foreach ($this->aQueries as $oSQLQuery)
|
||||
@@ -93,36 +92,33 @@ class SQLUnionQuery extends SQLQuery
|
||||
// Render SELECTS without orderby/limit/count
|
||||
$aSelects[] = $oSQLQuery->RenderSelect(array(), $aArgs, 0, 0, false, $bBeautifulQuery);
|
||||
}
|
||||
$sSelects = '('.implode(")$sLineSep UNION$sLineSep(", $aSelects).')';
|
||||
|
||||
if ($bGetCount)
|
||||
if ($iLimitCount > 0)
|
||||
{
|
||||
$sFrom = "($sLineSep$sSelects$sLineSep) as __selects__";
|
||||
$sSQL = "SELECT$sLineSep COUNT(*) AS COUNT$sLineSep FROM $sFrom$sLineSep";
|
||||
$sLimit = 'LIMIT '.$iLimitStart.', '.$iLimitCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLimit = '';
|
||||
}
|
||||
|
||||
if ($bGetCount)
|
||||
{
|
||||
$sSelects = '('.implode(" $sLimit)$sLineSep UNION$sLineSep(", $aSelects)." $sLimit)";
|
||||
$sFrom = "($sLineSep$sSelects$sLineSep) as __selects__";
|
||||
$sSQL = "SELECT COUNT(*) AS COUNT FROM (SELECT$sLineSep 1 $sLineSep FROM $sFrom$sLineSep) AS _union_tatooine_";
|
||||
}
|
||||
else
|
||||
{
|
||||
$aSelects = array();
|
||||
foreach ($this->aQueries as $oSQLQuery)
|
||||
{
|
||||
// Render SELECT without orderby/limit/count
|
||||
$aSelects[] = $oSQLQuery->RenderSelect(array(), $aArgs, 0, 0, false, $bBeautifulQuery);
|
||||
}
|
||||
$sSelect = $this->aQueries[0]->RenderSelectClause();
|
||||
$sOrderBy = $this->aQueries[0]->RenderOrderByClause($aOrderBy);
|
||||
if (!empty($sOrderBy))
|
||||
{
|
||||
$sOrderBy = "ORDER BY $sOrderBy$sLineSep";
|
||||
}
|
||||
if ($iLimitCount > 0)
|
||||
{
|
||||
$sLimit = 'LIMIT '.$iLimitStart.', '.$iLimitCount;
|
||||
$sOrderBy = "ORDER BY $sOrderBy$sLineSep $sLimit";
|
||||
$sSQL = '('.implode(")$sLineSep UNION$sLineSep (", $aSelects).')'.$sLineSep.$sOrderBy;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLimit = '';
|
||||
$sSQL = '('.implode(" $sLimit)$sLineSep UNION$sLineSep (", $aSelects)." $sLimit)";
|
||||
}
|
||||
$sSQL = $sSelects.$sLineSep.$sOrderBy.' '.$sLimit;
|
||||
}
|
||||
return $sSQL;
|
||||
}
|
||||
|
||||
@@ -338,6 +338,8 @@ abstract class User extends cmdbAbstractObject
|
||||
'bulkread' => $this->GetGrantAsHtml($sClass, UR_ACTION_BULK_READ),
|
||||
'write' => $this->GetGrantAsHtml($sClass, UR_ACTION_MODIFY),
|
||||
'bulkwrite' => $this->GetGrantAsHtml($sClass, UR_ACTION_BULK_MODIFY),
|
||||
'delete' => $this->GetGrantAsHtml($sClass, UR_ACTION_DELETE),
|
||||
'bulkdelete' => $this->GetGrantAsHtml($sClass, UR_ACTION_BULK_DELETE),
|
||||
'stimuli' => $sStimuli,
|
||||
);
|
||||
}
|
||||
@@ -350,6 +352,8 @@ abstract class User extends cmdbAbstractObject
|
||||
$aDisplayConfig['bulkread'] = array('label' => Dict::S('UI:UserManagement:Action:BulkRead'), 'description' => Dict::S('UI:UserManagement:Action:BulkRead+'));
|
||||
$aDisplayConfig['write'] = array('label' => Dict::S('UI:UserManagement:Action:Modify'), 'description' => Dict::S('UI:UserManagement:Action:Modify+'));
|
||||
$aDisplayConfig['bulkwrite'] = array('label' => Dict::S('UI:UserManagement:Action:BulkModify'), 'description' => Dict::S('UI:UserManagement:Action:BulkModify+'));
|
||||
$aDisplayConfig['delete'] = array('label' => Dict::S('UI:UserManagement:Action:Delete'), 'description' => Dict::S('UI:UserManagement:Action:Delete+'));
|
||||
$aDisplayConfig['bulkdelete'] = array('label' => Dict::S('UI:UserManagement:Action:BulkDelete'), 'description' => Dict::S('UI:UserManagement:Action:BulkDelete+'));
|
||||
$aDisplayConfig['stimuli'] = array('label' => Dict::S('UI:UserManagement:Action:Stimuli'), 'description' => Dict::S('UI:UserManagement:Action:Stimuli+'));
|
||||
$oPage->table($aDisplayConfig, $aDisplayData);
|
||||
}
|
||||
@@ -1153,7 +1157,7 @@ class UserRights
|
||||
self::$m_aAdmins = array();
|
||||
self::$m_aPortalUsers = array();
|
||||
}
|
||||
if (!isset($_SESSION))
|
||||
if (!isset($_SESSION) && !utils::IsModeCLI())
|
||||
{
|
||||
session_name('itop-'.md5(APPROOT));
|
||||
session_start();
|
||||
|
||||
@@ -52,7 +52,7 @@ abstract class ValueSetDefinition
|
||||
}
|
||||
|
||||
|
||||
public function GetValues($aArgs, $sContains = '')
|
||||
public function GetValues($aArgs, $sContains = '', $sOperation = 'contains')
|
||||
{
|
||||
if (!$this->m_bIsLoaded)
|
||||
{
|
||||
@@ -93,12 +93,16 @@ abstract class ValueSetDefinition
|
||||
class ValueSetObjects extends ValueSetDefinition
|
||||
{
|
||||
protected $m_sContains;
|
||||
protected $m_sOperation;
|
||||
protected $m_sFilterExpr; // in OQL
|
||||
protected $m_sValueAttCode;
|
||||
protected $m_aOrderBy;
|
||||
protected $m_aExtraConditions;
|
||||
private $m_bAllowAllData;
|
||||
private $m_aModifierProperties;
|
||||
private $m_bSort;
|
||||
private $m_iLimit;
|
||||
|
||||
|
||||
/**
|
||||
* @param hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending
|
||||
@@ -106,12 +110,15 @@ class ValueSetObjects extends ValueSetDefinition
|
||||
public function __construct($sFilterExp, $sValueAttCode = '', $aOrderBy = array(), $bAllowAllData = false, $aModifierProperties = array())
|
||||
{
|
||||
$this->m_sContains = '';
|
||||
$this->m_sOperation = '';
|
||||
$this->m_sFilterExpr = $sFilterExp;
|
||||
$this->m_sValueAttCode = $sValueAttCode;
|
||||
$this->m_aOrderBy = $aOrderBy;
|
||||
$this->m_bAllowAllData = $bAllowAllData;
|
||||
$this->m_aModifierProperties = $aModifierProperties;
|
||||
$this->m_aExtraConditions = array();
|
||||
$this->m_bSort = true;
|
||||
$this->m_iLimit = 0;
|
||||
}
|
||||
|
||||
public function SetModifierProperty($sPluginClass, $sProperty, $value)
|
||||
@@ -163,11 +170,11 @@ class ValueSetObjects extends ValueSetDefinition
|
||||
return new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs);
|
||||
}
|
||||
|
||||
public function GetValues($aArgs, $sContains = '')
|
||||
public function GetValues($aArgs, $sContains = '', $sOperation = 'contains')
|
||||
{
|
||||
if (!$this->m_bIsLoaded || ($sContains != $this->m_sContains))
|
||||
if (!$this->m_bIsLoaded || ($sContains != $this->m_sContains) || ($sOperation != $this->m_sOperation))
|
||||
{
|
||||
$this->LoadValues($aArgs, $sContains);
|
||||
$this->LoadValues($aArgs, $sContains, $sOperation);
|
||||
$this->m_bIsLoaded = true;
|
||||
}
|
||||
// The results are already filtered and sorted (on friendly name)
|
||||
@@ -175,9 +182,10 @@ class ValueSetObjects extends ValueSetDefinition
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
protected function LoadValues($aArgs, $sContains = '')
|
||||
protected function LoadValues($aArgs, $sContains = '', $sOperation = 'contains')
|
||||
{
|
||||
$this->m_sContains = $sContains;
|
||||
$this->m_sOperation = $sOperation;
|
||||
|
||||
$this->m_aValues = array();
|
||||
|
||||
@@ -202,12 +210,67 @@ class ValueSetObjects extends ValueSetDefinition
|
||||
}
|
||||
}
|
||||
|
||||
$oValueExpr = new ScalarExpression('%'.$sContains.'%');
|
||||
$oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias());
|
||||
$oNewCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
|
||||
$oFilter->AddConditionExpression($oNewCondition);
|
||||
$oExpression = DBObjectSearch::GetPolymorphicExpression($oFilter->GetClass(), 'friendlyname');
|
||||
$aFields = $oExpression->ListRequiredFields();
|
||||
$sClass = $oFilter->GetClass();
|
||||
foreach($aFields as $sField)
|
||||
{
|
||||
$aFieldItems = explode('.', $sField);
|
||||
if ($aFieldItems[0] != $sClass)
|
||||
{
|
||||
$sOperation = 'contains';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$oObjects = new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs);
|
||||
switch ($sOperation)
|
||||
{
|
||||
case 'equals_start_with':
|
||||
$aAttributes = MetaModel::GetFriendlyNameAttributeCodeList($oFilter->GetClass());
|
||||
$sClassAlias = $oFilter->GetClassAlias();
|
||||
$aFilters = array();
|
||||
// Equals first
|
||||
$oValueExpr = new ScalarExpression($sContains);
|
||||
foreach($aAttributes as $sAttribute)
|
||||
{
|
||||
$oNewFilter = $oFilter->DeepClone();
|
||||
$oNameExpr = new FieldExpression($sAttribute, $sClassAlias);
|
||||
$oCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
|
||||
$oNewFilter->AddConditionExpression($oCondition);
|
||||
$aFilters[] = $oNewFilter;
|
||||
}
|
||||
// start with next
|
||||
$oValueExpr = new ScalarExpression($sContains.'%');
|
||||
foreach($aAttributes as $sAttribute)
|
||||
{
|
||||
$oNewFilter = $oFilter->DeepClone();
|
||||
$oNameExpr = new FieldExpression($sAttribute, $sClassAlias);
|
||||
$oCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
|
||||
$oNewFilter->AddConditionExpression($oCondition);
|
||||
$aFilters[] = $oNewFilter;
|
||||
}
|
||||
// Unions are much faster than OR conditions
|
||||
$oFilter = new DBUnionSearch($aFilters);
|
||||
break;
|
||||
|
||||
default:
|
||||
$oValueExpr = new ScalarExpression('%'.$sContains.'%');
|
||||
$oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias());
|
||||
$oNewCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
|
||||
$oFilter->AddConditionExpression($oNewCondition);
|
||||
break;
|
||||
}
|
||||
|
||||
$oObjects = new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs, null, $this->m_iLimit, 0, $this->m_bSort);
|
||||
if (empty($this->m_sValueAttCode))
|
||||
{
|
||||
$aAttToLoad = array($oFilter->GetClassAlias() => array('friendlyname'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAttToLoad = array($oFilter->GetClassAlias() => array($this->m_sValueAttCode));
|
||||
}
|
||||
$oObjects->OptimizeColumnLoad($aAttToLoad);
|
||||
while ($oObject = $oObjects->Fetch())
|
||||
{
|
||||
if (empty($this->m_sValueAttCode))
|
||||
@@ -231,6 +294,22 @@ class ValueSetObjects extends ValueSetDefinition
|
||||
{
|
||||
return $this->m_sFilterExpr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $iLimit
|
||||
*/
|
||||
public function SetLimit($iLimit)
|
||||
{
|
||||
$this->m_iLimit = $iLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $bSort
|
||||
*/
|
||||
public function SetSort($bSort)
|
||||
{
|
||||
$this->m_bSort = $bSort;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,4 +5,4 @@ $complement-light: #d6e8ef;
|
||||
$frame-background-color: #F1F1F1;
|
||||
$text-color: #000;
|
||||
// Beware the version number MUST be enclosed with quotes otherwise v2.3.0 becomes v2 0.3 .0
|
||||
$version: "v2.4.0-beta";
|
||||
$version: "v2.4.0";
|
||||
BIN
css/font-combodo/combodo-webfont.ttf
Normal file
BIN
css/font-combodo/combodo-webfont.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -21,7 +21,7 @@ OS2Version: 0
|
||||
OS2_WeightWidthSlopeOnly: 0
|
||||
OS2_UseTypoMetrics: 1
|
||||
CreationTime: 1463745065
|
||||
ModificationTime: 1464178421
|
||||
ModificationTime: 1506001058
|
||||
OS2TypoAscent: 0
|
||||
OS2TypoAOffset: 1
|
||||
OS2TypoDescent: 0
|
||||
@@ -35,7 +35,6 @@ HheadAscent: 0
|
||||
HheadAOffset: 1
|
||||
HheadDescent: 0
|
||||
HheadDOffset: 1
|
||||
OS2Vendor: 'PfEd'
|
||||
MarkAttachClasses: 1
|
||||
DEI: 91125
|
||||
Encoding: ISO8859-1
|
||||
@@ -47,7 +46,7 @@ FitToEm: 0
|
||||
WinInfo: 0 31 10
|
||||
BeginPrivate: 0
|
||||
EndPrivate
|
||||
BeginChars: 256 8
|
||||
BeginChars: 256 11
|
||||
|
||||
StartChar: zero
|
||||
Encoding: 48 48 0
|
||||
@@ -210,7 +209,7 @@ StartChar: three
|
||||
Encoding: 51 51 3
|
||||
Width: 1022
|
||||
VWidth: 0
|
||||
Flags: MO
|
||||
Flags: M
|
||||
LayerCount: 3
|
||||
Fore
|
||||
SplineSet
|
||||
@@ -261,11 +260,13 @@ StartChar: C
|
||||
Encoding: 67 67 4
|
||||
Width: 1080
|
||||
VWidth: 0
|
||||
Flags: HW
|
||||
Flags: W
|
||||
HStem: -112 36<398.67 444.211> 97 36<463.993 575.071> 116 37<411.524 459.906> 250 37<334.123 402.464> 335 37<749.246 821.773> 387 37<836.543 929.295> 396 37<873.093 933.545> 442 37<475 482 739.647 795.664> 621 37<286.042 389.13> 650 37<510.192 579.789>
|
||||
VStem: 53 37<216.048 298> 218 37<457.867 579.651> 272 36<60.6299 128.446> 439 37<479.452 577.67> 451 37<-73.2171 5.85426> 472 37<568.829 649.107> 553 37<359.872 417.574> 651 38<-34.3438 62.6665> 718 38<8.82031 164.606> 934 38<341.569 396>
|
||||
LayerCount: 3
|
||||
Fore
|
||||
SplineSet
|
||||
641 -116 m 4x9b20
|
||||
641 -116 m 4x9b39f0
|
||||
637 -116 633 -115 630 -113 c 4
|
||||
624 -110 616 -102 616 -88 c 4
|
||||
616 -84 617 -80 618 -75 c 4
|
||||
@@ -275,14 +276,14 @@ SplineSet
|
||||
651 31 641 52 624 75 c 4
|
||||
609 94 595 108 586 115 c 5
|
||||
562 107 523 97 500 97 c 6
|
||||
499 97 l 6xdb20
|
||||
499 97 l 6xdb39f0
|
||||
479 97 468 105 460 111 c 4
|
||||
457 114 455 115 453 116 c 4
|
||||
450 116 438 112 423 104 c 4
|
||||
412 98 405 94 401 90 c 5
|
||||
411 80 436 61 448 52 c 4
|
||||
460 43 468 37 473 32 c 4
|
||||
485 20 488 -4 488 -20 c 4
|
||||
485 20 488 -4 488 -20 c 4xb93af0
|
||||
488 -27 487 -33 487 -36 c 4
|
||||
485 -55 477 -90 452 -105 c 4
|
||||
444 -110 435 -112 426 -112 c 4
|
||||
@@ -321,10 +322,10 @@ SplineSet
|
||||
219 484 218 493 218 504 c 4
|
||||
218 526 222 550 231 575 c 4
|
||||
237 593 255 636 284 651 c 4
|
||||
293 656 305 658 320 658 c 4xb9a0
|
||||
293 656 305 658 320 658 c 4
|
||||
342 658 367 653 389 644 c 4
|
||||
416 633 437 617 452 597 c 4
|
||||
472 571 476 537 476 508 c 4
|
||||
472 571 476 537 476 508 c 4xb9bcf0
|
||||
476 497 476 487 475 479 c 5
|
||||
482 479 l 5
|
||||
505 499 l 5
|
||||
@@ -352,7 +353,7 @@ SplineSet
|
||||
766 473 767 473 768 473 c 4
|
||||
787 473 808 460 831 446 c 4
|
||||
845 437 865 424 873 424 c 4
|
||||
874 424 l 6x9d60
|
||||
874 424 l 6x9d79f0
|
||||
875 424 880 425 884 426 c 4
|
||||
897 429 915 433 930 433 c 4
|
||||
956 433 965 421 969 412 c 4
|
||||
@@ -362,7 +363,7 @@ SplineSet
|
||||
916 289 911 288 905 288 c 4
|
||||
888 288 863 299 835 311 c 4
|
||||
810 322 780 335 766 335 c 4
|
||||
765 335 764 335 764 335 c 4
|
||||
764 335 l 4
|
||||
763 335 757 331 748 315 c 4
|
||||
741 301 734 283 727 264 c 4
|
||||
721 248 715 231 708 216 c 5
|
||||
@@ -370,7 +371,7 @@ SplineSet
|
||||
756 69 755 58 753 47 c 4
|
||||
748 19 727 -22 708 -51 c 4
|
||||
697 -68 687 -82 677 -93 c 4
|
||||
663 -109 652 -116 641 -116 c 4x9b20
|
||||
663 -109 652 -116 641 -116 c 4x9b39f0
|
||||
308 85 m 5
|
||||
308 83 312 72 340 46 c 4
|
||||
357 30 374 18 374 18 c 6
|
||||
@@ -387,14 +388,14 @@ SplineSet
|
||||
383 55 362 72 362 90 c 4
|
||||
362 92 362 93 362 95 c 4
|
||||
363 100 366 113 402 134 c 4
|
||||
410 138 435 153 453 153 c 4xb9a0
|
||||
410 138 435 153 453 153 c 4xb9baf0
|
||||
455 153 458 152 460 152 c 4
|
||||
470 150 476 145 482 141 c 4
|
||||
488 136 491 133 499 133 c 6
|
||||
500 133 l 6xd920
|
||||
500 133 l 6xd93af0
|
||||
521 133 562 145 581 153 c 6
|
||||
589 156 l 5
|
||||
596 153 l 6xb920
|
||||
596 153 l 6xb93af0
|
||||
612 146 637 119 654 97 c 4
|
||||
670 75 689 44 689 16 c 4
|
||||
689 13 689 10 688 7 c 4
|
||||
@@ -413,7 +414,7 @@ SplineSet
|
||||
868 337 893 326 903 325 c 5
|
||||
907 329 916 340 924 359 c 4
|
||||
932 377 934 390 934 396 c 4
|
||||
933 396 932 396 930 396 c 4xdb20
|
||||
933 396 932 396 930 396 c 4xdb3af0
|
||||
919 396 902 392 892 390 c 4
|
||||
886 389 881 388 878 388 c 4
|
||||
876 388 875 387 873 387 c 4
|
||||
@@ -433,9 +434,9 @@ SplineSet
|
||||
629 559 619 566 619 566 c 6
|
||||
615 569 l 5
|
||||
580 633 l 5
|
||||
566 639 539 650 520 650 c 4x9d60
|
||||
566 639 539 650 520 650 c 4
|
||||
514 650 512 650 511 649 c 4
|
||||
510 648 509 644 509 637 c 4
|
||||
510 648 509 644 509 637 c 4x9d79f0
|
||||
509 629 510 618 514 602 c 4
|
||||
517 589 520 577 523 569 c 5
|
||||
562 561 l 5
|
||||
@@ -446,7 +447,7 @@ SplineSet
|
||||
435 465 l 6
|
||||
437 474 439 491 439 510 c 4
|
||||
439 533 436 558 423 575 c 4
|
||||
400 605 354 621 320 621 c 4x99a0
|
||||
400 605 354 621 320 621 c 4x99bcf0
|
||||
310 621 304 619 301 618 c 4
|
||||
281 608 255 548 255 504 c 4
|
||||
255 497 255 490 257 484 c 4
|
||||
@@ -475,22 +476,25 @@ SplineSet
|
||||
424 204 390 196 377 186 c 4
|
||||
330 149 310 105 308 85 c 5
|
||||
EndSplineSet
|
||||
Validated: 1
|
||||
EndChar
|
||||
|
||||
StartChar: I
|
||||
Encoding: 73 73 5
|
||||
Width: 1024
|
||||
VWidth: 0
|
||||
Flags: HW
|
||||
Flags: W
|
||||
HStem: -154 166<226 365 659 798> 126 26<498.267 525.733> 151 131<288 343 681 735> 313 132<288 343 681 735> 330 32<424.389 599.754> 443 26<498.267 525.733> 584 184<226 365 659 798>
|
||||
VStem: 51 175<12 151 445 584> 365 132<74 126 469 521> 366 31<282 313> 527 132<74 126 469 521> 627 31<282 313> 798 175<12 151 445 584>
|
||||
LayerCount: 3
|
||||
Fore
|
||||
SplineSet
|
||||
51 -154 m 1
|
||||
51 -154 m 1x8308
|
||||
51 768 l 1
|
||||
973 768 l 1
|
||||
973 -154 l 1
|
||||
51 -154 l 1
|
||||
497 469 m 2
|
||||
51 -154 l 1x8308
|
||||
497 469 m 1x87a8
|
||||
502 469 507 470 512 470 c 0
|
||||
517 470 522 469 527 469 c 1
|
||||
527 521 l 1
|
||||
@@ -498,35 +502,34 @@ SplineSet
|
||||
512 702 l 1
|
||||
414 604 l 1
|
||||
497 521 l 1
|
||||
497 469 l 1
|
||||
497 469 l 2
|
||||
497 469 l 1x87a8
|
||||
653 417 m 1
|
||||
681 445 l 1
|
||||
798 445 l 1
|
||||
798 445 l 1x9328
|
||||
798 584 l 1
|
||||
659 584 l 1
|
||||
659 467 l 1
|
||||
633 440 l 1
|
||||
643 433 649 425 653 417 c 1
|
||||
366 282 m 1
|
||||
366 282 m 1xb348
|
||||
366 313 l 1
|
||||
288 313 l 1
|
||||
206 396 l 1
|
||||
108 298 l 1
|
||||
206 200 l 1
|
||||
288 282 l 1
|
||||
366 282 l 1
|
||||
366 282 l 1xb348
|
||||
343 445 m 1
|
||||
371 417 l 1
|
||||
375 425 381 433 391 440 c 1
|
||||
365 467 l 1
|
||||
365 584 l 1
|
||||
365 584 l 1x9388
|
||||
226 584 l 1
|
||||
226 445 l 1
|
||||
343 445 l 1
|
||||
371 178 m 1
|
||||
343 151 l 1
|
||||
226 151 l 1
|
||||
226 151 l 1xa388
|
||||
226 12 l 1
|
||||
365 12 l 1
|
||||
365 129 l 1
|
||||
@@ -535,7 +538,7 @@ SplineSet
|
||||
818 396 m 1
|
||||
735 313 l 1
|
||||
658 313 l 1
|
||||
658 282 l 1
|
||||
658 282 l 1xb318
|
||||
735 282 l 1
|
||||
818 200 l 1
|
||||
916 298 l 1
|
||||
@@ -543,12 +546,12 @@ SplineSet
|
||||
653 178 m 1
|
||||
649 170 643 162 633 155 c 1
|
||||
659 129 l 1
|
||||
659 12 l 1
|
||||
659 12 l 1xa328
|
||||
798 12 l 1
|
||||
798 151 l 1
|
||||
681 151 l 1
|
||||
653 178 l 1
|
||||
527 126 m 1
|
||||
527 126 m 1xc3a8
|
||||
522 126 517 126 512 126 c 0
|
||||
507 126 502 126 497 126 c 1
|
||||
497 74 l 1
|
||||
@@ -556,8 +559,7 @@ SplineSet
|
||||
512 -106 l 1
|
||||
610 -8 l 1
|
||||
527 74 l 1
|
||||
527 126 l 1
|
||||
527 126 l 1
|
||||
527 126 l 1xc3a8
|
||||
610 348 m 0
|
||||
584 337 549 330 512 330 c 0
|
||||
475 330 441 337 414 348 c 0
|
||||
@@ -567,9 +569,9 @@ SplineSet
|
||||
449 157 479 152 512 152 c 0
|
||||
545 152 575 157 598 167 c 0
|
||||
616 174 627 184 627 192 c 2
|
||||
627 356 l 1
|
||||
627 356 l 1xcb58
|
||||
622 353 616 351 610 348 c 0
|
||||
512 443 m 1
|
||||
512 443 m 1x8f58
|
||||
479 443 449 438 426 428 c 0
|
||||
408 421 397 410 397 402 c 0
|
||||
397 394 408 384 426 377 c 0
|
||||
@@ -577,8 +579,7 @@ SplineSet
|
||||
545 362 575 367 598 377 c 0
|
||||
616 384 627 394 627 402 c 0
|
||||
627 410 616 421 598 428 c 0
|
||||
575 438 545 443 512 443 c 1
|
||||
512 443 l 1
|
||||
575 438 545 443 512 443 c 1x8f58
|
||||
EndSplineSet
|
||||
Validated: 5
|
||||
EndChar
|
||||
@@ -587,7 +588,8 @@ StartChar: four
|
||||
Encoding: 52 52 6
|
||||
Width: 1024
|
||||
VWidth: 0
|
||||
Flags: H
|
||||
HStem: -2 41<389.544 635.489> 292 109<316 441 550 675> 639 41<389.544 636.396>
|
||||
VStem: 117 41<241.556 436.857> 441 109<167 292 401 525> 868 41<249.643 435.223>
|
||||
LayerCount: 3
|
||||
Fore
|
||||
SplineSet
|
||||
@@ -607,7 +609,6 @@ SplineSet
|
||||
909 288 892 238 861 189 c 0
|
||||
835 149 801 111 757 77 c 1
|
||||
801 -67 l 1
|
||||
801 -67 l 1
|
||||
649 63 m 1
|
||||
733 17 l 1
|
||||
710 93 l 1
|
||||
@@ -618,7 +619,6 @@ SplineSet
|
||||
158 174 317 39 513 39 c 0
|
||||
552 39 592 49 634 59 c 2
|
||||
649 63 l 1
|
||||
649 63 l 1
|
||||
675 306 m 1
|
||||
675 298 667 292 657 292 c 2
|
||||
550 292 l 1
|
||||
@@ -640,7 +640,6 @@ SplineSet
|
||||
657 401 l 2
|
||||
667 401 675 394 675 386 c 2
|
||||
675 306 l 1
|
||||
675 306 l 1
|
||||
EndSplineSet
|
||||
Validated: 5
|
||||
EndChar
|
||||
@@ -649,15 +648,17 @@ StartChar: D
|
||||
Encoding: 68 68 7
|
||||
Width: 1080
|
||||
VWidth: 0
|
||||
Flags: HW
|
||||
Flags: W
|
||||
HStem: 198 131<79.9424 131.341> 306 98<835.102 921.871> 353 100<731.982 810.871>
|
||||
VStem: 238 219<460.138 583.719> 292 88<67.6511 114.863> 369 100<-72.2559 6.9753> 667 66<3.74069 76.8123>
|
||||
LayerCount: 3
|
||||
Fore
|
||||
SplineSet
|
||||
469 -14 m 4
|
||||
469 -14 m 4x26
|
||||
469 -45 459 -89 425 -89 c 4
|
||||
397 -89 372 -53 369 -41 c 4
|
||||
397 -89 372 -53 369 -41 c 4x26
|
||||
365 -27 363 7 363 7 c 5
|
||||
363 7 292 63 292 88 c 4
|
||||
363 7 292 63 292 88 c 4x2a
|
||||
292 113 317 164 366 202 c 4
|
||||
388 219 439 225 439 225 c 5
|
||||
439 225 414 269 373 269 c 4
|
||||
@@ -669,7 +670,7 @@ SplineSet
|
||||
119 206 108 198 97 198 c 4
|
||||
78 198 76 234 76 261 c 4
|
||||
76 268 76 274 76 279 c 4
|
||||
76 288 76 295 76 295 c 6
|
||||
76 295 l 6
|
||||
76 295 82 320 96 328 c 4
|
||||
97 328 98 329 99 329 c 4
|
||||
121 329 217 268 217 268 c 6
|
||||
@@ -696,12 +697,12 @@ SplineSet
|
||||
570 401 569 394 569 388 c 4
|
||||
569 355 614 330 614 330 c 5
|
||||
614 330 646 364 662 384 c 4
|
||||
678 404 734 453 763 453 c 4
|
||||
678 404 734 453 763 453 c 4xb2
|
||||
790 453 841 404 867 404 c 4
|
||||
878 404 902 413 924 413 c 4
|
||||
938 413 945 409 945 396 c 4
|
||||
945 371 922 318 905 307 c 4
|
||||
903 306 902 306 899 306 c 4
|
||||
903 306 902 306 899 306 c 4x52
|
||||
872 306 795 353 761 353 c 4
|
||||
758 353 756 353 754 352 c 4
|
||||
723 342 708 263 682 213 c 5
|
||||
@@ -714,11 +715,232 @@ SplineSet
|
||||
667 64 605 129 586 138 c 5
|
||||
565 130 522 118 499 118 c 4
|
||||
475 118 470 137 453 137 c 4
|
||||
437 137 380 108 380 93 c 4
|
||||
437 137 380 108 380 93 c 4x2a
|
||||
380 77 446 36 460 23 c 4
|
||||
465 18 469 3 469 -14 c 4
|
||||
465 18 469 3 469 -14 c 4x26
|
||||
EndSplineSet
|
||||
Validated: 1
|
||||
EndChar
|
||||
|
||||
StartChar: E
|
||||
Encoding: 69 69 8
|
||||
Width: 1024
|
||||
VWidth: 0
|
||||
HStem: -65 248<767.992 903.557> 62.9598 56.9516<226.56 349.224 705.189 710> 143 26.9554<256.859 324.845> 192.776 27.2245<289.957 314.952> 295.071 27.9295<269.575 354.789> 344 66<376.038 439.962> 433 25<407.015 431.988> 469 248<767.951 904.873>
|
||||
VStem: 66.5097 115.469<193.203 298.14> 204 32.9583<187.285 267.499> 257.966 57.0345<194.835 224.243> 335.831 30.8205<177.895 239.59> 388.713 44.4108<157.773 270.37> 407 25<433.012 457.985> 442 55.4336<365.791 447.874> 711 249<-8.06335 62 583 662.557>
|
||||
LayerCount: 3
|
||||
Fore
|
||||
SplineSet
|
||||
279 573 m 0x7ffb
|
||||
292 573 313 570 343 563 c 0
|
||||
462 535 489 420 496 389 c 0
|
||||
496.963 384.737 497.434 380.795 497.434 377.167 c 0
|
||||
497.434 354.414 478.912 344 447 344 c 0
|
||||
422.333 344 394.111 344.889 359.074 344.889 c 0
|
||||
341.556 344.889 322.333 344.667 301 344 c 0
|
||||
237 342 192 300 183 241 c 0
|
||||
182.31 236.477 181.979 231.948 181.979 227.44 c 0
|
||||
181.979 173.142 230.063 121.847 279 120 c 0
|
||||
280.57 119.941 282.134 119.911 283.69 119.911 c 0
|
||||
334.636 119.911 377.296 151.452 387 199 c 0
|
||||
388.159 204.678 388.713 210.303 388.713 215.813 c 0
|
||||
388.713 257.852 356.437 293.232 314 295 c 0
|
||||
312.865 295.047 311.742 295.071 310.63 295.071 c 0
|
||||
264.267 295.071 236.958 255.02 236.958 229.128 c 0
|
||||
236.958 206.914 253.918 170.972 286 170 c 0
|
||||
287.107 169.97 288.186 169.955 289.238 169.955 c 0
|
||||
323.358 169.955 329.15 185.419 334 199 c 0
|
||||
335.206 202.378 335.831 206.221 335.831 210.207 c 0
|
||||
335.831 222.743 329.657 236.689 316 242 c 0
|
||||
298 249 291 238 290 234 c 0
|
||||
289 228 294 220 299 220 c 0
|
||||
306 220 316 220 315 206 c 0
|
||||
314.143 195.714 302.265 192.776 292.592 192.776 c 0
|
||||
290.98 192.776 289.429 192.857 288 193 c 0
|
||||
278.231 193.977 257.966 202.588 257.966 228.155 c 0
|
||||
257.966 248.46 275.443 271.256 306.289 271.256 c 0
|
||||
308.143 271.256 310.047 271.172 312 271 c 0
|
||||
351.28 267.429 366.651 246.325 366.651 219.783 c 0
|
||||
366.651 216.594 366.429 213.326 366 210 c 0
|
||||
362 179 343 143 284 143 c 0
|
||||
225 143 204 192 204 229 c 0
|
||||
204 266 232 322 318 323 c 0
|
||||
318.502 323.006 319.002 323.009 319.501 323.009 c 0
|
||||
394.354 323.009 433.124 257.543 433.124 205.254 c 0
|
||||
433.124 198.198 432.418 191.383 431 185 c 0
|
||||
420.148 134.686 398.59 62.9598 273.187 62.9598 c 0
|
||||
271.478 62.9598 269.749 62.9731 268 63 c 0
|
||||
134.539 65.8599 66.5097 196.855 66.5097 295.718 c 0
|
||||
66.5097 300.562 66.673 305.329 67 310 c 0
|
||||
74 410 112 447 146 480 c 0
|
||||
204.987 537.114 264.85 531.109 264.85 543.245 c 0
|
||||
264.85 544.071 264.573 544.981 264 546 c 0
|
||||
260.913 551.732 257.827 557.659 257.827 562.495 c 0
|
||||
257.827 568.625 262.788 573 279 573 c 0x7ffb
|
||||
408 478 m 0
|
||||
389 478 374 463 374 444 c 0
|
||||
374 425 389 410 408 410 c 0
|
||||
427 410 442 425 442 444 c 0
|
||||
442 463 427 478 408 478 c 0
|
||||
835 717 m 0
|
||||
904 717 960 662 960 593 c 0
|
||||
960 524 904 469 835 469 c 0
|
||||
798 469 751 495 731 526 c 1
|
||||
515 456 l 1
|
||||
503 483 491 498 481 511 c 1
|
||||
712 583 l 2
|
||||
712 586 711 590 711 593 c 0
|
||||
711 662 766 717 835 717 c 0
|
||||
462 207 m 1
|
||||
727 121 l 1
|
||||
747 155 795 183 834 183 c 0
|
||||
903 183 958 128 958 59 c 0
|
||||
958 -10 903 -65 834 -65 c 0x9ff3
|
||||
765 -65 710 -10 710 59 c 0
|
||||
710 60 710 61 710 62 c 2
|
||||
456 143 l 1
|
||||
458.679 159.077 462.157 171.165 462.157 197.076 c 0
|
||||
462.157 200.176 462.107 203.474 462 207 c 1
|
||||
407 445 m 0x1ff7
|
||||
407 453 412 458 420 458 c 0
|
||||
428 458 432 453 432 445 c 0
|
||||
432 437 428 433 420 433 c 0
|
||||
412 433 407 437 407 445 c 0x1ff7
|
||||
EndSplineSet
|
||||
Validated: 1
|
||||
EndChar
|
||||
|
||||
StartChar: F
|
||||
Encoding: 70 70 9
|
||||
Width: 1024
|
||||
VWidth: 0
|
||||
HStem: -36 87<438.038 591.036> 87 39<470.027 570.5> 163 41<517.914 555.989> 241 41<519.089 577.135> 317 43<482.813 612.995> 394 100<654.807 741.193> 528 39<697.004 734.996>
|
||||
VStem: 177 177<195.689 296.938> 387 50<156.758 272.234> 469 87<171.273 203.985> 588 47<139.283 231.811> 669 67<122.953 266.087> 697 38<528.004 566.995> 750 85<426.5 559.5>
|
||||
LayerCount: 3
|
||||
Fore
|
||||
SplineSet
|
||||
502 742 m 0xfff4
|
||||
522 742 553 738 599 727 c 0
|
||||
780 684 822 509 833 462 c 0
|
||||
835 456 835 450 835 444 c 0
|
||||
835 409 806 392 758 392 c 0
|
||||
721 392 678 394 624 394 c 0
|
||||
597 394 568 393 535 392 c 0
|
||||
437 388 368 325 355 235 c 0
|
||||
354 228 354 222 354 215 c 0
|
||||
354 132 426 55 501 51 c 0
|
||||
504 51 507 51 510 51 c 0
|
||||
587 51 652 99 666 171 c 0
|
||||
668 180 669 188 669 196 c 0
|
||||
669 260 620 313 555 317 c 0
|
||||
553 317 550 317 548 317 c 0
|
||||
478 317 437 256 437 218 c 0
|
||||
437 184 463 127 512 126 c 0
|
||||
514 126 516 126 518 126 c 0
|
||||
569 126 578 150 586 171 c 0
|
||||
588 176 588 181 588 187 c 0
|
||||
588 207 579 228 557 237 c 0
|
||||
550 240 545 241 540 241 c 0
|
||||
525 241 520 230 518 225 c 0
|
||||
516 216 524 204 532 204 c 0
|
||||
543 204 556 202 556 183 c 0
|
||||
556 166 541 163 525 163 c 0
|
||||
522 163 518 163 515 163 c 0
|
||||
499 164 469 177 469 217 c 0
|
||||
469 247 497 282 543 282 c 0
|
||||
546 282 549 282 552 282 c 0
|
||||
611 277 635 243 635 202 c 0
|
||||
635 197 635 193 634 188 c 0
|
||||
628 141 598 87 508 87 c 0
|
||||
418 87 387 162 387 218 c 0
|
||||
387 274 430 358 561 360 c 0
|
||||
562 360 563 360 564 360 c 0
|
||||
677 360 736 262 736 182 c 0
|
||||
736 171 735 160 733 150 c 0
|
||||
716 74 683 -36 494 -36 c 0
|
||||
491 -36 487 -36 484 -36 c 0
|
||||
280 -32 177 170 177 321 c 0
|
||||
177 328 178 335 178 342 c 0
|
||||
188 495 246 549 298 600 c 0
|
||||
388 687 479 677 479 696 c 0
|
||||
479 697 479 698 478 700 c 0
|
||||
473 709 469 718 469 725 c 0
|
||||
469 735 477 742 502 742 c 0xfff4
|
||||
698 597 m 0
|
||||
669 597 646 574 646 545 c 0
|
||||
646 516 669 494 698 494 c 0
|
||||
727 494 750 516 750 545 c 0
|
||||
750 574 727 597 698 597 c 0
|
||||
697 547 m 0xffec
|
||||
697 560 703 567 716 567 c 0
|
||||
729 567 735 560 735 547 c 0
|
||||
735 534 729 528 716 528 c 0
|
||||
703 528 697 534 697 547 c 0xffec
|
||||
EndSplineSet
|
||||
Validated: 1
|
||||
EndChar
|
||||
|
||||
StartChar: O
|
||||
Encoding: 79 79 10
|
||||
Width: 1024
|
||||
VWidth: 0
|
||||
HStem: 1.59961 8<801.97 829.007> 20 35.2002<801.975 810.774 823.574 824.837> 33.5996 5.60059<810.774 817.806> 48.7998 6.40039<810.774 818.736> 61.5996 8.7998<801.043 829.91> 434.399 245.601<441.712 567.228>
|
||||
VStem: 780.375 8.7998<21.8033 49.6942> 801.975 8.7998<20 33.5996 39.2002 48.7998> 819.574 8.80078<40.0451 47.9513> 841.175 8.7998<21.5374 50.3356>
|
||||
LayerCount: 3
|
||||
Fore
|
||||
SplineSet
|
||||
504.375 680 m 0x8fc0
|
||||
672.375 680 816.375 560 846.774 395.2 c 0
|
||||
877.175 230.399 785.975 67.2002 629.175 7.2002 c 0
|
||||
621.975 4.7998 613.975 8 611.574 15.2002 c 2
|
||||
533.175 218.399 l 2
|
||||
530.774 225.6 533.975 234.399 541.175 236.8 c 0
|
||||
587.574 254.399 613.975 301.6 605.175 350.399 c 0
|
||||
596.375 399.2 553.975 434.399 504.375 434.399 c 0
|
||||
454.774 434.399 413.175 399.2 404.375 350.399 c 0
|
||||
395.574 301.6 421.175 254.399 467.574 236.8 c 0
|
||||
474.774 234.399 477.975 225.6 475.574 218.399 c 2
|
||||
397.975 15.2002 l 2
|
||||
395.574 8 386.774 4.7998 379.574 7.2002 c 0
|
||||
222.774 67.2002 131.574 230.399 161.975 395.2 c 0
|
||||
192.375 560 336.375 680 504.375 680 c 0x8fc0
|
||||
815.574 70.3994 m 0
|
||||
834.774 70.3994 849.975 55.2002 849.975 36 c 0
|
||||
849.975 16.7998 834.774 1.59961 815.574 1.59961 c 0
|
||||
796.375 1.59961 780.375 16.7998 780.375 36 c 0
|
||||
780.375 55.2002 796.375 70.3994 815.574 70.3994 c 0
|
||||
815.574 61.5996 m 0
|
||||
801.175 61.5996 789.175 50.3994 789.175 36 c 0
|
||||
789.175 21.5996 801.175 9.59961 815.574 9.59961 c 0
|
||||
829.975 9.59961 841.175 21.5996 841.175 36 c 0
|
||||
841.175 50.3994 829.975 61.5996 815.574 61.5996 c 0
|
||||
814.774 39.2002 m 2xbfc0
|
||||
816.375 39.2002 817.975 40 818.774 40.7998 c 0
|
||||
819.574 41.5996 819.574 42.3994 819.574 44 c 0
|
||||
819.574 45.5996 819.574 46.3994 818.774 47.2002 c 0
|
||||
817.975 48 816.375 48.7998 814.774 48.7998 c 2
|
||||
810.774 48.7998 l 1
|
||||
810.774 39.2002 l 1
|
||||
814.774 39.2002 l 2xbfc0
|
||||
810.774 33.5996 m 1
|
||||
810.774 20 l 1
|
||||
801.975 20 l 1
|
||||
801.975 55.2002 l 1xcfc0
|
||||
815.574 55.2002 l 2x9fc0
|
||||
820.375 55.2002 822.774 54.3994 825.175 52.7998 c 0
|
||||
827.574 51.2002 828.375 48.7998 828.375 45.5996 c 0
|
||||
828.375 43.2002 827.574 41.5996 826.774 40 c 0
|
||||
825.975 38.3994 824.375 36.7998 821.975 36 c 1
|
||||
823.574 36 824.375 35.2002 825.175 34.3994 c 0
|
||||
825.975 33.5996 827.574 32 828.375 29.5996 c 2
|
||||
833.175 20 l 1
|
||||
823.574 20 l 1xcfc0
|
||||
819.574 28.7998 l 2
|
||||
818.774 30.3994 817.175 31.2002 816.375 32 c 0
|
||||
815.574 32.7998 814.774 33.5996 813.175 33.5996 c 2
|
||||
810.774 33.5996 l 1
|
||||
EndSplineSet
|
||||
Validated: 524321
|
||||
EndChar
|
||||
EndChars
|
||||
EndSplineFont
|
||||
|
||||
Binary file not shown.
@@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: 'CombodoRegular';
|
||||
src: url('combodo-webfont.woff2?v=1.0') format('woff2'),
|
||||
url('combodo-webfont.woff?v=1.0') format('woff'),
|
||||
url('combodo-webfont.ttf?v=1.0') format('truetype');
|
||||
src: url('combodo-webfont.woff2?v=2.0') format('woff2'),
|
||||
url('combodo-webfont.woff?v=2.0') format('woff'),
|
||||
url('combodo-webfont.ttf?v=2.0') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
|
||||
@@ -193,7 +193,16 @@
|
||||
.fc-combodo-icon:before {
|
||||
content: "D";
|
||||
}
|
||||
.fc-itophub-icon:before {
|
||||
content: "E";
|
||||
}
|
||||
.fc-chameleon-icon:before {
|
||||
content: "F";
|
||||
}
|
||||
.fc-itop-icon:before {
|
||||
content: "I";
|
||||
}
|
||||
.fc-opensource-icon:before {
|
||||
content: "O";
|
||||
}
|
||||
|
||||
|
||||
50
css/font-combodo/glyphs/E.svg
Executable file
50
css/font-combodo/glyphs/E.svg
Executable file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1000"
|
||||
height="1000"
|
||||
viewBox="0 0 264.58333 264.58334"
|
||||
version="1.1"
|
||||
id="svg909">
|
||||
<defs
|
||||
id="defs903" />
|
||||
<metadata
|
||||
id="metadata906">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
transform="matrix(2.6189878,0,0,2.6189878,-138.11438,-66.566639)"
|
||||
id="layer1">
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.40000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 77.776825,48.628779 c -3.105953,0.0165 -2.465143,1.56905 -1.672249,3.00189 0.969595,1.75214 -6.046384,0.53457 -12.856064,7.17372 -3.69523,3.60269 -7.8302,7.46233 -8.56485,18.39112 -0.73465,10.9288 6.57401,26.601051 21.834325,26.890351 14.098468,0.26727 16.523001,-7.762201 17.760671,-13.268961 1.323287,-5.88768 -2.939907,-15.10068 -12.294338,-14.96704 -9.354428,0.13364 -12.428178,6.14692 -12.428178,10.15597 0,4.00904 2.27182,9.35447 8.686288,9.35447 6.414468,0 8.552552,-3.87524 8.953457,-7.2161 0.400905,-3.34087 -1.12866,-6.23284 -5.863206,-6.68176 -3.664545,-0.34747 -5.823431,2.30622 -5.896281,4.44314 -0.100228,2.93996 2.194808,3.98392 3.307291,4.04264 1.112483,0.0587 2.766575,-0.003 2.856155,-1.33635 0.10023,-1.49182 -0.935023,-1.63676 -1.686717,-1.62005 -0.534409,0.0119 -1.147985,-0.88438 -0.985986,-1.50379 0.121989,-0.46643 0.78549,-1.62036 2.790009,-0.81855 2.004523,0.8018 2.544982,3.13823 2.021065,4.67723 -0.534538,1.57021 -1.18617,3.2909 -5.228621,3.17397 -3.536694,-0.1023 -5.411874,-4.25964 -5.328354,-6.68177 0.0939,-2.724 3.190312,-7.1826 8.402068,-6.91534 5.211754,0.26728 8.953352,5.07775 7.884274,10.42314 -1.069079,5.34539 -6.013196,8.82024 -11.759488,8.55297 -5.746294,-0.26727 -11.359094,-6.68189 -10.423654,-13.09636 0.93544,-6.41447 5.87967,-10.95789 12.828675,-11.22516 6.949005,-0.26727 11.885592,0.016 15.894636,0.016 4.009047,0 6.155487,-1.61955 5.353677,-4.96042 -0.8018,-3.34086 -3.786135,-15.85543 -16.689419,-18.91977 -3.29736,-0.78307 -5.483391,-1.09268 -6.895186,-1.0852 z m 13.978992,10.35854 a 3.685268,3.685268 0 0 1 3.685563,3.68505 3.685268,3.685268 0 0 1 -3.685563,3.68556 3.685268,3.685268 0 0 1 -3.685048,-3.68556 3.685268,3.685268 0 0 1 3.685048,-3.68505 z"
|
||||
id="path882" />
|
||||
<path
|
||||
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 138.24445,32.953249 a 13.49711,13.49711 0 0 0 -13.49685,13.49685 13.49711,13.49711 0 0 0 0.0465,1.06195 l -25.043431,7.84087 c 1.104251,1.4075 2.257151,3.10658 3.611151,6.01255 l 23.55566,-7.5799 a 13.49711,13.49711 0 0 0 11.32696,6.1619 13.49711,13.49711 0 0 0 13.49737,-13.49737 13.49711,13.49711 0 0 0 -13.49737,-13.49685 z"
|
||||
id="rect827" />
|
||||
<path
|
||||
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 97.624193,88.491979 c 0.07421,3.57897 -0.303877,5.04652 -0.587044,6.95772 l 27.570411,8.739001 a 13.49711,13.49711 0 0 0 -0.0134,0.37258 13.49711,13.49711 0 0 0 13.49737,13.49737 13.49711,13.49711 0 0 0 13.49685,-13.49737 13.49711,13.49711 0 0 0 -13.49685,-13.496851 13.49711,13.49711 0 0 0 -11.65201,6.71794 z"
|
||||
id="rect827-1" />
|
||||
<circle
|
||||
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path888"
|
||||
cx="93.031555"
|
||||
cy="62.530666"
|
||||
r="1.3701637" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
41
css/font-combodo/glyphs/F.svg
Executable file
41
css/font-combodo/glyphs/F.svg
Executable file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1000"
|
||||
height="1000"
|
||||
viewBox="0 0 264.58333 264.58334"
|
||||
version="1.1"
|
||||
id="svg909">
|
||||
<defs
|
||||
id="defs903" />
|
||||
<metadata
|
||||
id="metadata906">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(0,-32.41665)"
|
||||
id="layer1">
|
||||
<path
|
||||
style="fill:#1b1b1b;fill-opacity:1;stroke:#000000;stroke-width:1.71210456;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 128.74663,48.188011 c -13.29429,0.07062 -10.55146,6.715944 -7.15766,12.848874 4.15012,7.499617 -25.880108,2.288099 -55.027316,30.705397 -15.81655,15.420458 -33.515303,31.940728 -36.659797,78.718798 -3.144494,46.77813 28.138482,113.85946 93.456613,115.09774 60.34513,1.14398 70.72277,-33.22425 76.02032,-56.79463 5.66401,-25.20081 -12.58357,-64.63485 -52.62298,-64.06284 -40.0394,0.57201 -53.195848,26.31042 -53.195848,43.47021 0,17.15974 9.723978,40.03957 37.179578,40.03957 27.4556,0 36.60716,-16.58704 38.32314,-30.88679 1.71598,-14.2998 -4.83096,-26.67818 -25.09606,-28.59968 -15.68521,-1.48726 -24.9258,9.87122 -25.23762,19.0178 -0.429,12.5838 9.39435,17.05222 14.15607,17.30356 4.76172,0.25125 11.84166,-0.0128 12.22509,-5.71993 0.42901,-6.38538 -4.00214,-7.00576 -7.21959,-6.93424 -2.28741,0.0509 -4.91368,-3.78538 -4.22028,-6.43661 0.52215,-1.99644 3.3621,-6.93557 11.94197,-3.50361 8.57988,3.43191 10.89319,13.43244 8.65069,20.01977 -2.28797,6.72091 -5.07712,14.08591 -22.37987,13.58542 -15.13797,-0.43787 -23.16423,-18.23237 -22.80675,-28.59972 0.40192,-11.65944 13.65537,-30.74341 35.96305,-29.59947 22.30767,1.14403 38.32269,21.7341 33.74675,44.61377 -4.57593,22.87966 -25.73805,37.75293 -50.33368,36.60894 -24.59564,-1.14398 -48.619888,-28.60023 -44.615958,-56.05584 4.00393,-27.45561 25.166518,-46.90263 54.910078,-48.04662 29.74356,-1.14398 50.87344,0.0685 68.0332,0.0685 17.15977,0 26.34709,-6.93209 22.91514,-21.23189 -3.43192,-14.29975 -16.20565,-67.865386 -71.43508,-80.981563 -14.11356,-3.351744 -23.47035,-4.676956 -29.5132,-4.644939 z m 59.83374,44.337259 a 15.77391,15.77391 0 0 1 15.77517,15.77298 15.77391,15.77391 0 0 1 -15.77517,15.77516 15.77391,15.77391 0 0 1 -15.77297,-15.77516 15.77391,15.77391 0 0 1 15.77297,-15.77298 z"
|
||||
id="path882" />
|
||||
<circle
|
||||
style="opacity:1;fill:#101010;fill-opacity:1;stroke:#000000;stroke-width:1.71210456;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path888"
|
||||
cx="194.04086"
|
||||
cy="107.69173"
|
||||
r="5.8646588" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
87
css/font-combodo/glyphs/O.svg
Executable file
87
css/font-combodo/glyphs/O.svg
Executable file
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="1000"
|
||||
height="1000"
|
||||
viewBox="0 0 264.58333 264.58334"
|
||||
version="1.1"
|
||||
id="svg876"
|
||||
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
|
||||
sodipodi:docname="O.svg">
|
||||
<defs
|
||||
id="defs870" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.35"
|
||||
inkscape:cx="-272.85714"
|
||||
inkscape:cy="560"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1005"
|
||||
inkscape:window-x="1911"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata873">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Calque 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-32.41664)">
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:middle;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:8.99672318;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 131.53572,50.179132 c -54.174274,0 -100.702568,38.6765 -110.575582,91.938598 -9.873159,53.26282 19.698102,106.06258 70.277674,125.4761 2.319548,0.89024 4.921621,-0.26836 5.811987,-2.58786 L 122.30183,199.2106 c 0.89023,-2.31957 -0.26838,-4.92164 -2.58789,-5.812 -14.87072,-5.70891 -23.515673,-21.14784 -20.612431,-36.80689 2.903191,-15.6588 16.504681,-26.96534 32.434211,-26.96534 15.92952,0 29.53338,11.30654 32.43657,26.96534 2.90326,15.65905 -5.74171,31.09798 -20.61242,36.80689 -2.31951,0.89036 -3.47812,3.49245 -2.58788,5.812 l 25.25202,65.79537 c 0.89038,2.31821 3.49074,3.47652 5.8096,2.58786 50.57958,-19.41352 80.15083,-72.21328 70.27768,-125.4761 -9.87301,-53.262098 -56.4013,-91.938598 -110.57557,-91.938598 z"
|
||||
id="path3773"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ssccscsssccccss" />
|
||||
<g
|
||||
style="display:inline"
|
||||
id="g3797"
|
||||
transform="matrix(1.2200654,0,0,1.2200654,455.86197,1099.5367)"
|
||||
inkscape:export-filename="/home/rafael/workspace/logo-osi/3/png/logo396x412.png"
|
||||
inkscape:export-xdpi="48.18"
|
||||
inkscape:export-ydpi="48.18">
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.25831962;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m -183.5617,-698.57555 c -5.02556,0 -9.12392,4.09113 -9.12392,9.10782 0,5.01668 4.09836,9.10781 9.12392,9.10781 5.02556,0 9.12392,-4.09113 9.12392,-9.10781 0,-5.01669 -4.09836,-9.10782 -9.12392,-9.10782 z m 0,2.25596 c 3.80399,0 6.8633,3.05458 6.8633,6.85186 0,3.79727 -3.05931,6.85119 -6.8633,6.85119 -3.80399,0 -6.86397,-3.05392 -6.86397,-6.85119 0,-3.79728 3.05998,-6.85186 6.86397,-6.85186 z"
|
||||
id="path3015"
|
||||
inkscape:connector-curvature="0" />
|
||||
<g
|
||||
aria-label="R"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:0%;font-family:OpenSymbol;-inkscape-font-specification:'OpenSymbol Bold';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
|
||||
id="text3793">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m -183.7552,-690.46513 q 0.74769,0 1.06902,-0.27807 0.3275,-0.27807 0.3275,-0.91454 0,-0.63028 -0.3275,-0.90217 -0.32133,-0.27189 -1.06902,-0.27189 h -1.00105 v 2.36667 z m -1.00105,1.64369 v 3.4913 h -2.37902 v -9.22569 h 3.63342 q 1.82289,0 2.66946,0.61175 0.85274,0.61175 0.85274,1.93412 0,0.91454 -0.44491,1.50157 -0.43873,0.58703 -1.32855,0.8651 0.48817,0.11123 0.87128,0.50671 0.3893,0.38929 0.78477,1.18642 l 1.29147,2.62002 h -2.53351 l -1.12463,-2.29252 q -0.33986,-0.69208 -0.69208,-0.94543 -0.34604,-0.25335 -0.92689,-0.25335 z"
|
||||
style="font-size:12.65519524px;line-height:1.25"
|
||||
id="path863" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.6 KiB |
@@ -18,6 +18,9 @@ aIcons = {
|
||||
'combodo-icon': 'Combodo icon',
|
||||
'combodo-icon-o': 'Combodo icon (outline)',
|
||||
'itop-icon': 'iTop icon',
|
||||
'itophub-icon': 'iTop Hub icon',
|
||||
'chameleon-icon': 'Hub\'s Chameleon icon',
|
||||
'opensource-icon': 'Open Source Logo',
|
||||
}
|
||||
|
||||
function GenerateTable() {
|
||||
|
||||
BIN
css/font-open-sans/OpenSans-Bold-cyrillic-ext.woff2
Normal file
BIN
css/font-open-sans/OpenSans-Bold-cyrillic-ext.woff2
Normal file
Binary file not shown.
BIN
css/font-open-sans/OpenSans-Bold-cyrillic.woff2
Normal file
BIN
css/font-open-sans/OpenSans-Bold-cyrillic.woff2
Normal file
Binary file not shown.
BIN
css/font-open-sans/OpenSans-Bold-greek-ext.woff2
Normal file
BIN
css/font-open-sans/OpenSans-Bold-greek-ext.woff2
Normal file
Binary file not shown.
BIN
css/font-open-sans/OpenSans-Bold-greek.woff2
Normal file
BIN
css/font-open-sans/OpenSans-Bold-greek.woff2
Normal file
Binary file not shown.
BIN
css/font-open-sans/OpenSans-Bold-latin-ext.woff2
Normal file
BIN
css/font-open-sans/OpenSans-Bold-latin-ext.woff2
Normal file
Binary file not shown.
BIN
css/font-open-sans/OpenSans-Bold-latin.woff2
Normal file
BIN
css/font-open-sans/OpenSans-Bold-latin.woff2
Normal file
Binary file not shown.
BIN
css/font-open-sans/OpenSans-Bold-vietnamese.woff2
Normal file
BIN
css/font-open-sans/OpenSans-Bold-vietnamese.woff2
Normal file
Binary file not shown.
BIN
css/font-open-sans/OpenSans-Regular-cyrillic-ext.woff2
Normal file
BIN
css/font-open-sans/OpenSans-Regular-cyrillic-ext.woff2
Normal file
Binary file not shown.
BIN
css/font-open-sans/OpenSans-Regular-cyrillic.woff2
Normal file
BIN
css/font-open-sans/OpenSans-Regular-cyrillic.woff2
Normal file
Binary file not shown.
BIN
css/font-open-sans/OpenSans-Regular-greek-ext.woff2
Normal file
BIN
css/font-open-sans/OpenSans-Regular-greek-ext.woff2
Normal file
Binary file not shown.
BIN
css/font-open-sans/OpenSans-Regular-greek.woff2
Normal file
BIN
css/font-open-sans/OpenSans-Regular-greek.woff2
Normal file
Binary file not shown.
BIN
css/font-open-sans/OpenSans-Regular-latin-ext.woff2
Normal file
BIN
css/font-open-sans/OpenSans-Regular-latin-ext.woff2
Normal file
Binary file not shown.
BIN
css/font-open-sans/OpenSans-Regular-latin.woff2
Normal file
BIN
css/font-open-sans/OpenSans-Regular-latin.woff2
Normal file
Binary file not shown.
BIN
css/font-open-sans/OpenSans-Regular-vietnamese.woff2
Normal file
BIN
css/font-open-sans/OpenSans-Regular-vietnamese.woff2
Normal file
Binary file not shown.
112
css/font-open-sans/font-open-sans.css
Normal file
112
css/font-open-sans/font-open-sans.css
Normal file
@@ -0,0 +1,112 @@
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url('./OpenSans-Regular-cyrillic-ext.woff2') format('woff2');
|
||||
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url('./OpenSans-Regular-cyrillic.woff2') format('woff2');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url('./OpenSans-Regular-greek-ext.woff2') format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url('./OpenSans-Regular-greek.woff2') format('woff2');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url('./OpenSans-Regular-vietnamese.woff2') format('woff2');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url('./OpenSans-Regular-latin-ext.woff2') format('woff2');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url('./OpenSans-Regular-latin.woff2') format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Open Sans Bold'), local('OpenSans-Bold'), url('./OpenSans-Bold-cyrillic-ext.woff2') format('woff2');
|
||||
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Open Sans Bold'), local('OpenSans-Bold'), url('./OpenSans-Bold-cyrillic.woff2') format('woff2');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Open Sans Bold'), local('OpenSans-Bold'), url('./OpenSans-Bold-greek-ext.woff2') format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Open Sans Bold'), local('OpenSans-Bold'), url('./OpenSans-Bold-greek.woff2') format('woff2');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Open Sans Bold'), local('OpenSans-Bold'), url('./OpenSans-Bold-vietnamese.woff2') format('woff2');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Open Sans Bold'), local('OpenSans-Bold'), url('./OpenSans-Bold-latin-ext.woff2') format('woff2');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Open Sans Bold'), local('OpenSans-Bold'), url('./OpenSans-Bold-latin.woff2') format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
||||
}
|
||||
1824
css/light-grey.css
1824
css/light-grey.css
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,14 @@ body.printable-version {
|
||||
.ui-layout-content {
|
||||
padding-left: 10px;
|
||||
}
|
||||
.ui-layout-content .ui-tabs-nav li {
|
||||
/* Overriding jQuery UI theme to see active tab better */
|
||||
margin-bottom: 2px;
|
||||
|
||||
&.ui-tabs-active{
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.raw_output {
|
||||
font-family: Courier-New, Courier, Arial, Helvetica;
|
||||
@@ -107,6 +115,12 @@ table.listResults td .view-image {
|
||||
.view-image {
|
||||
display: inline-block;
|
||||
|
||||
img[src=""],
|
||||
img[src="null"] {
|
||||
// Hiding "broken" image when src is not set
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
&.dirty {
|
||||
// The image will be modified when saving the changes
|
||||
|
||||
@@ -835,7 +849,7 @@ table.listResults tr.even td.truncated, .wizContainer table.listResults tr.even
|
||||
}
|
||||
|
||||
/* Beware: IE6 does not support multiple selector with multiple classes, only the last class is used */
|
||||
table.listResults tr.even td.hover.truncated, , .wizContainer table.listResults tr.even td.hover.truncated {
|
||||
table.listResults tr.even td.hover.truncated, .wizContainer table.listResults tr.even td.hover.truncated {
|
||||
background: #fdf5d0 url(../images/truncated.png?v=#{$version}) bottom repeat-x;
|
||||
}
|
||||
|
||||
@@ -1245,6 +1259,18 @@ span.form_validation {
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
|
||||
/* Helper classes for object details display. */
|
||||
.one-col-details {
|
||||
min-width: 400px;
|
||||
max-width: 600px;
|
||||
}
|
||||
.n-cols-details {
|
||||
width: 100%;
|
||||
|
||||
> tbody > tr > td {
|
||||
min-width: 240px;
|
||||
}
|
||||
}
|
||||
.details {
|
||||
border-collapse: collapse;
|
||||
noborder-bottom: 2px #fff solid;
|
||||
@@ -1269,18 +1295,23 @@ fieldset .details>.field_container {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
&.field_large{
|
||||
&.field_large {
|
||||
display: inherit;
|
||||
|
||||
/* .field_label, .field_data */
|
||||
> div {
|
||||
display: inherit;
|
||||
|
||||
&.field_label{
|
||||
&.field_label {
|
||||
width: inherit;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
&.field_data {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* .field_value, .field_comments, .field_infos */
|
||||
> div {
|
||||
}
|
||||
@@ -1496,6 +1527,13 @@ fieldset .details>.field_container {
|
||||
}
|
||||
}
|
||||
}
|
||||
.one-col-details .details .field_container.field_small {
|
||||
div.field_label {
|
||||
/* On a single column, field labels can take more width but they are limited so it doesn't feel weird when all labels are short */
|
||||
width: 175px;
|
||||
max-width: inherit;
|
||||
}
|
||||
}
|
||||
/* This is extracted from the ".details > .field_container ..." because of the fullscreen option (element is moved at the end of the body */
|
||||
.field_input_text{
|
||||
border: none;
|
||||
@@ -1563,6 +1601,10 @@ fieldset .details>.field_container {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.ac_input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.field_input_extkey{
|
||||
display: table;
|
||||
width: 100%;
|
||||
@@ -1579,8 +1621,8 @@ fieldset .details>.field_container {
|
||||
|
||||
.field_input_btn{
|
||||
display: table-cell;
|
||||
width: 20px;
|
||||
margin-left: 0.4em;
|
||||
width: 25px;
|
||||
padding-left: 0.4em;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1674,6 +1716,7 @@ td.layout_cell {
|
||||
.dashlet-content {
|
||||
background: #fff;
|
||||
margin:0;
|
||||
overflow: auto;
|
||||
}
|
||||
table.prop_table {
|
||||
border-bottom: 2px solid #F9F9F1;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -21,13 +21,13 @@
|
||||
* Authent External
|
||||
* Module definition file for the "External Authentication" module
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-external/2.2.0',
|
||||
'authent-external/2.4.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
@@ -63,4 +63,3 @@ SetupWebPage::AddModule(
|
||||
'settings' => array(),
|
||||
)
|
||||
);
|
||||
?>
|
||||
|
||||
@@ -9,7 +9,7 @@ if (function_exists('ldap_connect'))
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-ldap/2.2.0',
|
||||
'authent-ldap/2.4.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
@@ -63,5 +63,3 @@ SetupWebPage::AddModule(
|
||||
);
|
||||
|
||||
} // if (function_exists('ldap_connect'))
|
||||
|
||||
?>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-local/2.2.0',
|
||||
'authent-local/2.4.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
@@ -40,5 +40,3 @@ SetupWebPage::AddModule(
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<module>itop-profiles-itil</module>
|
||||
<module>itop-welcome-itil</module>
|
||||
<module>itop-tickets</module>
|
||||
<module>itop-hub-connector</module>
|
||||
</modules>
|
||||
<mandatory>true</mandatory>
|
||||
</choice>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2">
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.4">
|
||||
<classes>
|
||||
<class id="Attachment" _delta="define">
|
||||
<parent>DBObject</parent>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2014 Combodo SARL
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -39,4 +39,3 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Attachments:NoAttachment' => 'Kein Attachment. ',
|
||||
'Attachments:PreviewNotAvailable' => 'Vorschau für diesen Attachment-Typ nicht verfügbar.',
|
||||
));
|
||||
?>
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-attachments/2.3.0',
|
||||
'itop-attachments/2.4.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
@@ -145,5 +145,3 @@ if (!class_exists('AttachmentInstaller'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -24,4 +24,4 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
'Attachment:Max_Ko' => '(Максимальный размер файла: %1$s кБ)',
|
||||
'Attachments:NoAttachment' => 'Нет вложений.',
|
||||
'Attachments:PreviewNotAvailable' => 'Предварительный просмотр не доступен для этого типа вложений.',
|
||||
));
|
||||
));
|
||||
|
||||
@@ -61,6 +61,7 @@ try
|
||||
catch (Exception $e)
|
||||
{
|
||||
$oPage->p('Error: '.$e->getMessage());
|
||||
IssueLog::Error($sOperation.' - '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
$oPage->output();
|
||||
@@ -156,6 +157,7 @@ EOF
|
||||
{
|
||||
$oRestoreMutex->Unlock();
|
||||
$oPage->p('Error: '.$e->getMessage());
|
||||
IssueLog::Error($sOperation.' - '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
$oPage->output();
|
||||
@@ -179,6 +181,6 @@ EOF
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
IssueLog::Error($e->getMessage());
|
||||
IssueLog::Error($sOperation.' - '.$e->getMessage());
|
||||
}
|
||||
|
||||
|
||||
@@ -211,7 +211,7 @@ catch(Exception $e)
|
||||
exit;
|
||||
}
|
||||
|
||||
$sZipArchiveFile = MakeArchiveFileName();
|
||||
$sZipArchiveFile = MakeArchiveFileName().'.tar.gz';
|
||||
echo date('Y-m-d H:i:s')." - Checking file: $sZipArchiveFile\n";
|
||||
|
||||
if (file_exists($sZipArchiveFile))
|
||||
@@ -223,7 +223,7 @@ if (file_exists($sZipArchiveFile))
|
||||
if ($iSize > $iMIN)
|
||||
{
|
||||
echo "Found the archive\n";
|
||||
$sOldArchiveFile = MakeArchiveFileName(time() - 86400); // yesterday's archive
|
||||
$sOldArchiveFile = MakeArchiveFileName(time() - 86400).'.tar.gz'; // yesterday's archive
|
||||
if (file_exists($sOldArchiveFile))
|
||||
{
|
||||
if ($aOldStat = stat($sOldArchiveFile))
|
||||
|
||||
@@ -99,8 +99,10 @@ class DBRestore extends DBBackup
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sFile A file with the extension .zip or .tar.gz
|
||||
* @param string $sFile A file with the extension .zip or .tar.gz
|
||||
* @param string $sEnvironment Target environment
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function RestoreFromCompressedBackup($sFile, $sEnvironment = 'production')
|
||||
{
|
||||
@@ -111,7 +113,7 @@ class DBRestore extends DBBackup
|
||||
{
|
||||
$this->LogInfo('zip file detected');
|
||||
$oArchive = new ZipArchiveEx();
|
||||
$res = $oArchive->open($sFile);
|
||||
$oArchive->open($sFile);
|
||||
}
|
||||
elseif (substr($sNormalizedFile, -7) == '.tar.gz')
|
||||
{
|
||||
@@ -125,21 +127,22 @@ class DBRestore extends DBBackup
|
||||
|
||||
// Load the database
|
||||
//
|
||||
$sDataDir = tempnam(SetupUtils::GetTmpDir(), 'itop-');
|
||||
unlink($sDataDir); // I need a directory, not a file...
|
||||
$sDataDir = APPROOT.'data/tmp-backup-'.rand(10000, getrandmax());
|
||||
|
||||
SetupUtils::builddir($sDataDir); // Here is the directory
|
||||
$oArchive->extractFileTo($sDataDir, 'itop-dump.sql');
|
||||
$oArchive->extractTo($sDataDir);
|
||||
|
||||
$sDataFile = $sDataDir.'/itop-dump.sql';
|
||||
$this->LoadDatabase($sDataFile);
|
||||
unlink($sDataFile);
|
||||
|
||||
// Update the code
|
||||
//
|
||||
$sDeltaFile = APPROOT.'data/'.$sEnvironment.'.delta.xml';
|
||||
if ($oArchive->hasFile('delta.xml') !== false)
|
||||
|
||||
if (is_file($sDataDir.'/delta.xml'))
|
||||
{
|
||||
// Extract and rename delta.xml => <env>.delta.xml;
|
||||
file_put_contents($sDeltaFile, $oArchive->getFromName('delta.xml'));
|
||||
rename($sDataDir.'/delta.xml', $sDeltaFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -149,16 +152,18 @@ class DBRestore extends DBBackup
|
||||
{
|
||||
SetupUtils::rrmdir(APPROOT.'data/production-modules/');
|
||||
}
|
||||
if ($oArchive->hasDir('production-modules/') !== false)
|
||||
if (is_dir($sDataDir.'/production-modules'))
|
||||
{
|
||||
$oArchive->extractDirTo(APPROOT.'data/', 'production-modules/');
|
||||
rename($sDataDir.'/production-modules', APPROOT.'data/production-modules/');
|
||||
}
|
||||
|
||||
$sConfigFile = APPROOT.'conf/'.$sEnvironment.'/config-itop.php';
|
||||
@chmod($sConfigFile, 0770); // Allow overwriting the file
|
||||
$oArchive->extractFileTo(APPROOT.'conf/'.$sEnvironment, 'config-itop.php');
|
||||
rename($sDataDir.'/config-itop.php', $sConfigFile);
|
||||
@chmod($sConfigFile, 0444); // Read-only
|
||||
|
||||
SetupUtils::rrmdir($sDataDir);
|
||||
|
||||
$oEnvironment = new RunTimeEnvironment($sEnvironment);
|
||||
$oEnvironment->CompileFrom($sEnvironment);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2014 Combodo SARL
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
|
||||
@@ -291,4 +291,3 @@ class ItopBackup extends ModuleHandlerAPI
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-backup/2.2.0',
|
||||
'itop-backup/2.4.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
@@ -56,5 +56,3 @@ SetupWebPage::AddModule(
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
||||
|
||||
@@ -47,4 +47,3 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
'bkp-wait-restore' => 'Пожалуйста, дождитесь завершения восстановления...',
|
||||
'bkp-success-restore' => 'Восстановление успешно завершено.',
|
||||
));
|
||||
?>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2">
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.4">
|
||||
<classes>
|
||||
<class id="lnkVirtualDeviceToVolume" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-bridge-virtualization-storage/2.3.0',
|
||||
'itop-bridge-virtualization-storage/2.4.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
@@ -43,6 +43,3 @@ SetupWebPage::AddModule(
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2">
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.4">
|
||||
<classes>
|
||||
<class id="Change" _delta="define">
|
||||
<parent>Ticket</parent>
|
||||
@@ -7,7 +7,7 @@
|
||||
<comment><![CDATA[/**
|
||||
* Persistent classes for a CMDB
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/]]></comment>
|
||||
<category>bizmodel,searchable,changemgmt</category>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2014 Combodo SARL
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-change-mgmt-itil/2.3.0',
|
||||
'itop-change-mgmt-itil/2.4.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
@@ -42,5 +42,3 @@ SetupWebPage::AddModule(
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2014 Combodo SARL
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-change-mgmt/2.3.0',
|
||||
'itop-change-mgmt/2.4.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
@@ -91,5 +91,3 @@ class ChangeManagementInstaller extends ModuleInstallerAPI
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1663,6 +1663,8 @@
|
||||
<attribute id="name"/>
|
||||
<attribute id="org_id"/>
|
||||
<attribute id="organization_name"/>
|
||||
<attribute id="location_id"/>
|
||||
<attribute id="location_name"/>
|
||||
<attribute id="finalclass"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
|
||||
@@ -395,8 +395,8 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:Group/Attribute:status+' => '',
|
||||
'Class:Group/Attribute:status/Value:implementation' => 'Implementation',
|
||||
'Class:Group/Attribute:status/Value:implementation+' => 'Implementation',
|
||||
'Class:Group/Attribute:status/Value:obsolete' => 'Veraltet',
|
||||
'Class:Group/Attribute:status/Value:obsolete+' => 'Veraltet',
|
||||
'Class:Group/Attribute:status/Value:obsolete' => 'Obsolet (Veraltet)',
|
||||
'Class:Group/Attribute:status/Value:obsolete+' => 'Obsolet (Veraltet)',
|
||||
'Class:Group/Attribute:status/Value:production' => 'Produktion',
|
||||
'Class:Group/Attribute:status/Value:production+' => 'Produktion',
|
||||
'Class:Group/Attribute:org_id' => 'Organisation',
|
||||
@@ -489,7 +489,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:Document/Attribute:status+' => '',
|
||||
'Class:Document/Attribute:status/Value:draft' => 'Entwurf',
|
||||
'Class:Document/Attribute:status/Value:draft+' => '',
|
||||
'Class:Document/Attribute:status/Value:obsolete' => 'Veraltet',
|
||||
'Class:Document/Attribute:status/Value:obsolete' => 'Obsolet (Veraltet)',
|
||||
'Class:Document/Attribute:status/Value:obsolete+' => '',
|
||||
'Class:Document/Attribute:status/Value:published' => 'Veröffentlicht',
|
||||
'Class:Document/Attribute:status/Value:published+' => '',
|
||||
@@ -1184,4 +1184,4 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:Subnet/Tab:FreeIPs-count' => 'Freie IPs: %1$s',
|
||||
'Class:Subnet/Tab:FreeIPs-explain' => 'Hier ist eine Aufstellung von 10 freien IP Adressen',
|
||||
));
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -32,7 +32,10 @@
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'Relation:impacts/Description' => 'Elements impacted by',
|
||||
'Relation:impacts/DownStream' => 'Impacts...',
|
||||
'Relation:impacts/DownStream+' => 'Elements impacted by',
|
||||
'Relation:impacts/UpStream' => 'Depends on......',
|
||||
'Relation:impacts/UpStream+' => 'Elements impacting',
|
||||
// Legacy entries
|
||||
'Relation:depends on/Description' => 'Elements impacting',
|
||||
'Relation:depends on/DownStream' => 'Depends on...',
|
||||
'Relation:depends on/UpStream' => 'Impacts...',
|
||||
|
||||
@@ -33,7 +33,10 @@
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'Relation:impacts/Description' => 'Elementos Impactados por',
|
||||
'Relation:impacts/DownStream' => 'Impacto...',
|
||||
'Relation:impacts/DownStream+' => 'Elementos Impactados por',
|
||||
'Relation:impacts/UpStream' => 'Depende de...',
|
||||
'Relation:impacts/UpStream+' => 'Elementos de los cuales depende',
|
||||
// Legacy entries
|
||||
'Relation:depends on/Description' => 'Elementos de los cuales depende',
|
||||
'Relation:depends on/DownStream' => 'Depende de...',
|
||||
'Relation:depends on/UpStream' => 'Impactos...',
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user