Merge branch 'develop' into feature/faf_event_service

This commit is contained in:
Eric Espie
2022-06-30 14:22:52 +02:00
2379 changed files with 100697 additions and 63433 deletions

View File

@@ -27,11 +27,14 @@ If you have an idea you're sure would benefit to all of iTop users, you may
[create a corresponding ticket](https://sourceforge.net/p/itop/tickets/new/) to submit it, but be warned that there are lots of good
reasons to refuse such changes.
### 📄 License
### 📄 License and copyright
iTop is distributed under the AGPL-3.0 license (see the [license.txt] file),
your code must comply with this license.
If you want to use another license, you may [create an extension][wiki new ext].
Combodo has the copyright on each and every source file in the iTop repository: please do not modify the existing file copyrights.
Anyhow, you are encouraged to signal your contribution by the mean of `@author` annotations.
If you want to use another license or keep the code ownership (copyright), you may [create an extension][wiki new ext].
[license.txt]: https://github.com/Combodo/iTop/blob/develop/license.txt
[wiki new ext]: https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Astart#by_writing_your_own_extension
@@ -141,9 +144,9 @@ Detailed procedure to work on fork and create PR is available [in GitHub help pa
### 🙏 We are thankful
We are thankful for all your contributions to the iTop universe! As a thank you gift, we will send stickers to every iTop (& extensions) contributors!
We are thankful for all your contributions to the iTop universe! As a thank you gift, we will send stickers to every iTop (& extensions) contributors!
Stickers' design might change from one year to another. For the first year we wanted to try a "craft beer label" look, see examples below:
We have one sticker per contribution type. You might get multiple stickers with one contribution though :)
* Bug hunter: Fix a bug
* Translator: Add/update translations
@@ -155,4 +158,6 @@ Stickers' design might change from one year to another. For the first year we wa
* Beta tester: Test and give feedback on beta releases
* Extension developer: Develop and publish an extension
![](.doc/contributing-guide/contributing-stickers-side-by-side.png)
Here is the design of each stickers for year 2022:
![iTop stickers 2022](.doc/contributing-guide/contributing-stickers-side-by-side.png)

View File

@@ -121,7 +121,6 @@ class UserRightsMatrix extends UserRightsAddOnAPI
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
// Maybe we should check that no other user with userid == 0 exists
CMDBObject::SetTrackInfo('Initialization');
$oUser = new UserLocal();
$oUser->Set('login', $sAdminUser);
$oUser->Set('password', $sAdminPwd);

View File

@@ -435,20 +435,18 @@ class UserRightsProfile extends UserRightsAddOnAPI
// Installation: create the very first user
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
CMDBObject::SetTrackInfo('Initialization');
CMDBObject::SetCurrentChangeFromParams('Initialization create administrator');
$iContactId = 0;
// Support drastic data model changes: no organization class (or not writable)!
if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization'))
{
if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization')) {
$oOrg = MetaModel::NewObject('Organization');
$oOrg->Set('name', 'My Company/Department');
$oOrg->Set('code', 'SOMECODE');
$iOrgId = $oOrg->DBInsertNoReload();
// Support drastic data model changes: no Person class (or not writable)!
if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person'))
{
if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person')) {
$oContact = MetaModel::NewObject('Person');
$oContact->Set('name', 'My last name');
$oContact->Set('first_name', 'My first name');

View File

@@ -508,24 +508,18 @@ class UserRightsProfile extends UserRightsAddOnAPI
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
// Create a change to record the history of the User object
/** @var \CMDBChange $oChange */
$oChange = MetaModel::NewObject("CMDBChange");
$oChange->Set("date", time());
$oChange->Set("userinfo", "Initialization");
CMDBObject::SetCurrentChangeFromParams('Initialization : create first user admin profile');
$iContactId = 0;
// Support drastic data model changes: no organization class (or not writable)!
if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization'))
{
if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization')) {
$oOrg = MetaModel::NewObject('Organization');
$oOrg->Set('name', 'My Company/Department');
$oOrg->Set('code', 'SOMECODE');
$oOrg::SetCurrentChange($oChange);
$iOrgId = $oOrg->DBInsertNoReload();
// Support drastic data model changes: no Person class (or not writable)!
if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person'))
{
if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person')) {
$oContact = MetaModel::NewObject('Person');
$oContact->Set('name', 'My last name');
$oContact->Set('first_name', 'My first name');
@@ -534,7 +528,6 @@ class UserRightsProfile extends UserRightsAddOnAPI
$oContact->Set('org_id', $iOrgId);
}
$oContact->Set('email', 'my.email@foo.org');
$oContact::SetCurrentChange($oChange);
$iContactId = $oContact->DBInsertNoReload();
}
}
@@ -543,24 +536,22 @@ class UserRightsProfile extends UserRightsAddOnAPI
$oUser = new UserLocal();
$oUser->Set('login', $sAdminUser);
$oUser->Set('password', $sAdminPwd);
if (MetaModel::IsValidAttCode('UserLocal', 'contactid') && ($iContactId != 0))
{
if (MetaModel::IsValidAttCode('UserLocal', 'contactid') && ($iContactId != 0)) {
$oUser->Set('contactid', $iContactId);
}
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
// Add this user to the very specific 'admin' profile
$oAdminProfile = MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => ADMIN_PROFILE_NAME), true /*all data*/);
if (is_object($oAdminProfile))
{
if (is_object($oAdminProfile)) {
$oUserProfile = new URP_UserProfile();
$oUserProfile->Set('profileid', $oAdminProfile->GetKey());
$oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
$oSet = DBObjectSet::FromObject($oUserProfile);
$oUser->Set('profile_list', $oSet);
}
$oUser::SetCurrentChange($oChange);
$iUserId = $oUser->DBInsertNoReload();
$oUser->DBInsertNoReload();
return true;
}

View File

@@ -568,14 +568,11 @@ class UserRightsProjection extends UserRightsAddOnAPI
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
// Create a change to record the history of the User object
$oChange = MetaModel::NewObject("CMDBChange");
$oChange->Set("date", time());
$oChange->Set("userinfo", "Initialization");
CMDBObject::SetCurrentChangeFromParams('Initialization : create first user admin');
$oOrg = new Organization();
$oOrg->Set('name', 'My Company/Department');
$oOrg->Set('code', 'SOMECODE');
$oOrg::SetCurrentChange($oChange);
$iOrgId = $oOrg->DBInsertNoReload();
$oContact = new Person();
@@ -584,7 +581,6 @@ class UserRightsProjection extends UserRightsAddOnAPI
//$oContact->Set('status', 'available');
$oContact->Set('org_id', $iOrgId);
$oContact->Set('email', 'my.email@foo.org');
$oContact::SetCurrentChange($oChange);
$iContactId = $oContact->DBInsertNoReload();
$oUser = new UserLocal();
@@ -592,7 +588,6 @@ class UserRightsProjection extends UserRightsAddOnAPI
$oUser->Set('password', $sAdminPwd);
$oUser->Set('contactid', $iContactId);
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
$oUser::SetCurrentChange($oChange);
$iUserId = $oUser->DBInsertNoReload();
// Add this user to the very specific 'admin' profile
@@ -600,7 +595,6 @@ class UserRightsProjection extends UserRightsAddOnAPI
$oUserProfile->Set('userid', $iUserId);
$oUserProfile->Set('profileid', ADMIN_PROFILE_ID);
$oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
$oUserProfile::SetCurrentChange($oChange);
$oUserProfile->DBInsertNoReload();
return true;
}

View File

@@ -342,13 +342,17 @@ JS
}
/**
* Important: For compatibility reasons, this function still allows to manipulate the $oPage. In that case, markup will be put above the real header of the panel.
* To insert something IN the panel, we now need to add UIBlocks in either the "subtitle" or "toolbar" sections of the array that will be returned.
* @param \WebPage $oPage warning, since 3.0.0 this parameter was kept for compatibility reason. You shouldn't write directly on the page !
* When writing to the page, markup will be put above the real header of the panel.
* To insert something IN the panel, we now need to add UIBlocks in either the "subtitle" or "toolbar" sections of the array that will be returned.
* @param bool $bEditMode Deprecated parameter in iTop 3.0.0, use {@see GetDisplayMode()} and ENUM_DISPLAY_MODE_* constants instead
*
* @param \WebPage $oPage
* @param bool $bEditMode Note that this parameter is no longer used in this method. Use {@see static::$sDisplayMode} instead
*
* @return array UIBlocks to be inserted in the "subtitle" and the "toolbar" sections of the ObjectDetails block. eg. ['subtitle' => [<BLOCK1>, <BLOCK2>], 'toolbar' => [<BLOCK3>]]
* @return array{
* subtitle: \Combodo\iTop\Application\UI\Base\UIBlock[],
* toolbar: \Combodo\iTop\Application\UI\Base\UIBlock[]
* }
* blocks to be inserted in the "subtitle" and the "toolbar" sections of the ObjectDetails block.
* eg. ['subtitle' => [<BLOCK1>, <BLOCK2>], 'toolbar' => [<BLOCK3>]]
*
* @throws \ApplicationException
* @throws \ArchivedObjectException
@@ -357,7 +361,10 @@ JS
* @throws \MySQLException
* @throws \OQLException
*
* @since 3.0.0 $bEditMode is deprecated and no longer used
* @since 3.0.0 $bEditMode is deprecated, see param documentation above
* @since 3.0.0 changed signature : method must return header content in an array (no more writing directly to the $oPage)
*
* @noinspection PhpUnusedParameterInspection
*/
public function DisplayBareHeader(WebPage $oPage, $bEditMode = false)
{

View File

@@ -9,6 +9,9 @@
use Combodo\iTop\Application\Branding;
use Combodo\iTop\Application\TwigBase\Twig\Extension;
use Twig\Environment;
use Twig\Loader\ChainLoader;
use Twig\Loader\FilesystemLoader;
/**
* Twig context for modules extending the login screen
@@ -217,14 +220,14 @@ class LoginTwigRenderer
$sTwigLoaderPath = $oLoginContext->GetTwigLoaderPath();
if ($sTwigLoaderPath != null)
{
$oExtensionLoader = new Twig_Loader_Filesystem();
$oExtensionLoader = new FilesystemLoader();
$oExtensionLoader->setPaths($sTwigLoaderPath);
$aTwigLoaders[] = $oExtensionLoader;
}
$this->aPostedVars = array_merge($this->aPostedVars, $oLoginContext->GetPostedVars());
}
$oCoreLoader = new Twig_Loader_Filesystem(array(), APPROOT.'templates');
$oCoreLoader = new FilesystemLoader(array(), APPROOT.'templates');
$aCoreTemplatesPaths = array('pages/login', 'pages/login/password');
// Having this path declared after the plugins let the plugins replace the core templates
$oCoreLoader->setPaths($aCoreTemplatesPaths);
@@ -232,8 +235,8 @@ class LoginTwigRenderer
$oCoreLoader->setPaths($aCoreTemplatesPaths, 'ItopCore');
$aTwigLoaders[] = $oCoreLoader;
$oLoader = new Twig_Loader_Chain($aTwigLoaders);
$this->oTwig = new Twig_Environment($oLoader);
$oLoader = new ChainLoader($aTwigLoaders);
$this->oTwig = new Environment($oLoader);
Extension::RegisterTwigExtensions($this->oTwig);
}
@@ -306,7 +309,7 @@ class LoginTwigRenderer
}
/**
* @return \Twig_Environment
* @return \Twig\Environment
*/
public function GetTwig()
{

View File

@@ -8,9 +8,9 @@ use DeprecatedCallsLog;
use Dict;
use Exception;
use MetaModel;
use Twig_Environment;
use Twig_SimpleFilter;
use Twig_SimpleFunction;
use Twig\Environment;
use Twig\TwigFilter;
use Twig\TwigFunction;
use utils;
DeprecatedCallsLog::NotifyDeprecatedFile('instead use sources/Application/TwigBase/Twig/Extension.php, which is loaded by the autoloader');
@@ -28,13 +28,13 @@ class TwigExtension
* Registers Twig extensions such as filters or functions.
* It allows us to access some stuff directly in twig.
*
* @param \Twig_Environment $oTwigEnv
* @param Environment $oTwigEnv
*/
public static function RegisterTwigExtensions(Twig_Environment &$oTwigEnv)
public static function RegisterTwigExtensions(Environment &$oTwigEnv)
{
// Filter to translate a string via the Dict::S function
// Usage in twig: {{ 'String:ToTranslate'|dict_s }}
$oTwigEnv->addFilter(new Twig_SimpleFilter('dict_s',
$oTwigEnv->addFilter(new TwigFilter('dict_s',
function ($sStringCode, $sDefault = null, $bUserLanguageOnly = false) {
return Dict::S($sStringCode, $sDefault, $bUserLanguageOnly);
})
@@ -42,7 +42,7 @@ class TwigExtension
// Filter to format a string via the Dict::Format function
// Usage in twig: {{ 'String:ToTranslate'|dict_format() }}
$oTwigEnv->addFilter(new Twig_SimpleFilter('dict_format',
$oTwigEnv->addFilter(new TwigFilter('dict_format',
function ($sStringCode, $sParam01 = null, $sParam02 = null, $sParam03 = null, $sParam04 = null) {
return Dict::Format($sStringCode, $sParam01, $sParam02, $sParam03, $sParam04);
})
@@ -51,16 +51,13 @@ class TwigExtension
// Filter to format output
// example a DateTime is converted to user format
// Usage in twig: {{ 'String:ToFormat'|output_format }}
$oTwigEnv->addFilter(new Twig_SimpleFilter('date_format',
$oTwigEnv->addFilter(new TwigFilter('date_format',
function ($sDate) {
try
{
if (preg_match('@^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d$@', trim($sDate)))
{
try {
if (preg_match('@^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d$@', trim($sDate))) {
return AttributeDateTime::GetFormat()->Format($sDate);
}
if (preg_match('@^\d\d\d\d-\d\d-\d\d$@', trim($sDate)))
{
if (preg_match('@^\d\d\d\d-\d\d-\d\d$@', trim($sDate))) {
return AttributeDate::GetFormat()->Format($sDate);
}
}
@@ -75,7 +72,7 @@ class TwigExtension
// Filter to format output
// example a DateTime is converted to user format
// Usage in twig: {{ 'String:ToFormat'|output_format }}
$oTwigEnv->addFilter(new Twig_SimpleFilter('size_format',
$oTwigEnv->addFilter(new TwigFilter('size_format',
function ($sSize) {
return utils::BytesToFriendlyFormat($sSize);
})
@@ -83,24 +80,25 @@ class TwigExtension
// Filter to enable base64 encode/decode
// Usage in twig: {{ 'String to encode'|base64_encode }}
$oTwigEnv->addFilter(new Twig_SimpleFilter('base64_encode', 'base64_encode'));
$oTwigEnv->addFilter(new Twig_SimpleFilter('base64_decode', 'base64_decode'));
$oTwigEnv->addFilter(new TwigFilter('base64_encode', 'base64_encode'));
$oTwigEnv->addFilter(new TwigFilter('base64_decode', 'base64_decode'));
// Filter to enable json decode (encode already exists)
// Usage in twig: {{ aSomeArray|json_decode }}
$oTwigEnv->addFilter(new Twig_SimpleFilter('json_decode', function ($sJsonString, $bAssoc = false) {
$oTwigEnv->addFilter(new TwigFilter('json_decode', function ($sJsonString, $bAssoc = false) {
return json_decode($sJsonString, $bAssoc);
})
);
// Filter to add itopversion to an url
$oTwigEnv->addFilter(new Twig_SimpleFilter('add_itop_version', function ($sUrl) {
$oTwigEnv->addFilter(new TwigFilter('add_itop_version', function ($sUrl) {
$sUrl = utils::AddParameterToUrl($sUrl, 'itopversion', ITOP_VERSION);
return $sUrl;
}));
// Filter to add a module's version to an url
$oTwigEnv->addFilter(new Twig_SimpleFilter('add_module_version', function ($sUrl, $sModuleName) {
$oTwigEnv->addFilter(new TwigFilter('add_module_version', function ($sUrl, $sModuleName) {
$sModuleVersion = utils::GetCompiledModuleVersion($sModuleName);
$sUrl = utils::AddParameterToUrl($sUrl, 'moduleversion', $sModuleVersion);
@@ -109,38 +107,36 @@ class TwigExtension
// Function to check our current environment
// Usage in twig: {% if is_development_environment() %}
$oTwigEnv->addFunction(new Twig_SimpleFunction('is_development_environment', function()
{
$oTwigEnv->addFunction(new TwigFunction('is_development_environment', function () {
return utils::IsDevelopmentEnvironment();
}));
// Function to get configuration parameter
// Usage in twig: {{ get_config_parameter('foo') }}
$oTwigEnv->addFunction(new Twig_SimpleFunction('get_config_parameter', function($sParamName)
{
$oTwigEnv->addFunction(new TwigFunction('get_config_parameter', function ($sParamName) {
$oConfig = MetaModel::GetConfig();
return $oConfig->Get($sParamName);
}));
// Function to get a module setting
// Usage in twig: {{ get_module_setting(<MODULE_CODE>, <PROPERTY_CODE> [, <DEFAULT_VALUE>]) }}
// since 3.0.0, but see N°4034 for upcoming evolutions in the 3.1
$oTwigEnv->addFunction(new Twig_SimpleFunction('get_module_setting', function (string $sModuleCode, string $sPropertyCode, $defaultValue = null) {
$oTwigEnv->addFunction(new TwigFunction('get_module_setting', function (string $sModuleCode, string $sPropertyCode, $defaultValue = null) {
$oConfig = MetaModel::GetConfig();
return $oConfig->GetModuleSetting($sModuleCode, $sPropertyCode, $defaultValue);
}));
// Function to get the URL of a static page in a module
// Usage in twig: {{ get_static_page_module_url('itop-my-module', 'path-to-my-page') }}
$oTwigEnv->addFunction(new Twig_SimpleFunction('get_static_page_module_url', function($sModuleName, $sPage)
{
$oTwigEnv->addFunction(new TwigFunction('get_static_page_module_url', function ($sModuleName, $sPage) {
return utils::GetAbsoluteUrlModulesRoot().$sModuleName.'/'.$sPage;
}));
// Function to get the URL of a php page in a module
// Usage in twig: {{ get_page_module_url('itop-my-module', 'path-to-my-my-page.php') }}
$oTwigEnv->addFunction(new Twig_SimpleFunction('get_page_module_url', function($sModuleName, $sPage)
{
$oTwigEnv->addFunction(new TwigFunction('get_page_module_url', function ($sModuleName, $sPage) {
return utils::GetAbsoluteUrlModulePage($sModuleName, $sPage);
}));
}

View File

@@ -21,6 +21,8 @@ use Combodo\iTop\Application\Helper\Session;
use Combodo\iTop\Application\UI\Base\iUIBlock;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
use ScssPhp\ScssPhp\Compiler;
use ScssPhp\ScssPhp\OutputStyle;
use ScssPhp\ScssPhp\ValueConverter;
/**
@@ -1940,20 +1942,25 @@ class utils
*/
public static function CompileCSSFromSASS($sSassContent, $aImportPaths = array(), $aVariables = array())
{
$oSass = new Compiler();
$oSass->setFormatter('ScssPhp\\ScssPhp\\Formatter\\Compressed');
$oSass = new Compiler();//['checkImportResolutions'=>true]);
$oSass->setOutputStyle(OutputStyle::COMPRESSED);
// Setting our variables
$oSass->setVariables($aVariables);
$aCssVariable = [];
foreach ($aVariables as $entry=>$value) {
$aCssVariable[$entry] = ValueConverter::parseValue($value);
}
$oSass->addVariables($aCssVariable);
// Setting our imports paths
$oSass->setImportPaths($aImportPaths);
// Temporary disabling max exec time while compiling
$iCurrentMaxExecTime = (int) ini_get('max_execution_time');
set_time_limit(0);
// Compiling SASS
$sCss = $oSass->compile($sSassContent);
//checkImportResolutions
$sCss = $oSass->compileString($sSassContent);
set_time_limit(intval($iCurrentMaxExecTime));
return $sCss;
return $sCss->getCss();
}
/**

View File

@@ -2,7 +2,7 @@
"type": "project",
"license": "AGPLv3",
"require": {
"php": ">=7.1.3 <8.0.0",
"php": ">=7.2.5 <8.0.0",
"ext-ctype": "*",
"ext-dom": "*",
"ext-gd": "*",
@@ -11,25 +11,24 @@
"ext-mysqli": "*",
"ext-soap": "*",
"combodo/tcpdf": "~6.4.4",
"guzzlehttp/guzzle": "^6.5",
"guzzlehttp/guzzle": "^6.5.8",
"laminas/laminas-mail": "^2.11",
"laminas/laminas-servicemanager": "^3.5",
"league/oauth2-google": "^3.0",
"nikic/php-parser": "~4.13.2",
"pear/archive_tar": "~1.4.14",
"pelago/emogrifier": "~3.1.0",
"scssphp/scssphp": "1.0.6",
"symfony/console": "~3.4.47",
"symfony/dotenv": "~3.4.47",
"symfony/framework-bundle": "~3.4.47",
"symfony/twig-bundle": "~3.4.47",
"symfony/yaml": "~3.4.47",
"thenetworg/oauth2-azure": "^2.0",
"twig/twig": "~1.42.5"
"scssphp/scssphp": "^1.10.3",
"symfony/console": "5.4.*",
"symfony/dotenv": "5.4.*",
"symfony/framework-bundle": "5.4.*",
"symfony/twig-bundle": "5.4.*",
"symfony/yaml": "5.4.*",
"thenetworg/oauth2-azure": "^2.0"
},
"require-dev": {
"symfony/stopwatch": "~3.4.47",
"symfony/web-profiler-bundle": "~3.4.47"
"symfony/stopwatch": "5.4.*",
"symfony/web-profiler-bundle": "5.4.*"
},
"suggest": {
"ext-libsodium": "Required to use the AttributeEncryptedString.",
@@ -41,7 +40,7 @@
},
"config": {
"platform": {
"php": "7.1.3"
"php": "7.2.5"
},
"vendor-dir": "lib",
"preferred-install": {

2512
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -614,7 +614,9 @@ abstract class CMDBObject extends DBObject
{
return $this->DBCloneTracked_Internal();
}
/*
* @deprecated 3.1.0 not used N°5232
*/
public function DBCloneTracked(CMDBChange $oChange, $newKey = null)
{
self::SetCurrentChange($oChange);

View File

@@ -592,46 +592,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'email_transport_smtp.oauth.provider' => [
'type' => 'string',
'description' => 'Email OAuth provider',
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'email_transport_smtp.oauth.client_id' => [
'type' => 'string',
'description' => 'Email OAuth client id',
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'email_transport_smtp.oauth.client_secret' => [
'type' => 'string',
'description' => 'Email OAuth client secret',
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'email_transport_smtp.oauth.access_token' => [
'type' => 'string',
'description' => 'Email OAuth access token',
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'email_transport_smtp.oauth.refresh_token' => [
'type' => 'string',
'description' => 'Email OAuth refresh token',
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'email_css' => [
'type' => 'string',
'description' => 'CSS that will override the standard stylesheet used for the notifications',

View File

@@ -155,7 +155,7 @@ class ormCaseLog {
break;
case static::ENUM_FORMAT_HTML:
$sHtmlEntry = $sTextEntry;
$sHtmlEntry = InlineImage::FixUrls($sTextEntry);
$sTextEntry = utils::HtmlToText($sHtmlEntry);
break;
}
@@ -723,7 +723,7 @@ class ormCaseLog {
}
else
{
$sRes = $sRaw;
$sRes = InlineImage::FixUrls($sRaw);
}
break;
}
@@ -758,6 +758,6 @@ class ormCaseLog {
}
$iPos += $this->m_aIndex[$index]['separator_length'];
$sText = substr($this->m_sLog, $iPos, $this->m_aIndex[$index]['text_length']);
return $sText;
return InlineImage::FixUrls($sText);
}
}

View File

@@ -596,10 +596,9 @@ class CheckStopWatchThresholds implements iBackgroundProcess
$oSW = $oObj->Get($sAttCode);
$oSW->MarkThresholdAsTriggered($iThreshold);
$oObj->Set($sAttCode, $oSW);
if($oObj->IsModified())
{
CMDBObject::SetTrackInfo("Automatic - threshold triggered");
if ($oObj->IsModified()) {
CMDBObject::SetCurrentChangeFromParams("Automatic - threshold triggered");
$oObj->DBUpdate();
}

View File

@@ -94,14 +94,13 @@ $ibo-field--enable-bulk--checkbox--margin-left: $ibo-spacing-300 !default;
max-width: 145px;
width: 30%;
}
.ibo-field--value {
margin-top: $ibo-field--value--margin-top--for-large; /* Mostly used to have a clear separation from elements in .ibo-field--comments */
}
/* N°4318 - Visible scrollbar background for large fields overflowing to ease "limits" visualization by the user */
.ibo-field--value > * {
--ibo-scrollbar--scrollbar-track-background-color: $ibo-field--value--scrollbar-track-background-color;
--ibo-scrollbar--scrollbar-track-background-color: #{$ibo-field--value--scrollbar-track-background-color};
}
/* Fullscreen mode */

View File

@@ -89,7 +89,7 @@ $ibo-panel--collapsible-toggler--color: $ibo-color-grey-700 !default;
.ibo-panel {
--ibo-main-color: map-get($ibo-panel-colors, 'neutral'); /* --ibo-main-color is to allow overload from custom dynamic value from the DM. The overload will be done through an additional CSS class of a particular DM class or DM attribute */
--ibo-main-color: #{map-get($ibo-panel-colors, 'neutral')}; /* --ibo-main-color is to allow overload from custom dynamic value from the DM. The overload will be done through an additional CSS class of a particular DM class or DM attribute */
position: relative;

View File

@@ -79,8 +79,8 @@ $ibo-pill-states-colors: (
/* Rules */
.ibo-pill {
/* --ibo-main-color-xxx is to allow overload from custom dynamic value from the DM. The overload will be done through an additional CSS class of a particular DM class or DM attribute */
--ibo-main-color--100: map-get(map-get($ibo-pill-states-colors, 'neutral'), 'primary-color');
--ibo-main-color--900: map-get(map-get($ibo-pill-states-colors, 'neutral'), 'secondary-color');
--ibo-main-color--100: #{map-get(map-get($ibo-pill-states-colors, 'neutral'), 'primary-color')};
--ibo-main-color--900: #{map-get(map-get($ibo-pill-states-colors, 'neutral'), 'secondary-color')};
@extend %ibo-fully-centered-content;
max-width: $ibo-pill--max-width;

View File

@@ -235,7 +235,7 @@ $ibo-quick-create--compartment--placeholder-hint--text-color: $ibo-color-grey-70
}
&:hover{
cursor: pointer;
@extend a:hover;
@extend a;
}
.highlight{

View File

@@ -14,4 +14,5 @@
@import "csv-import";
@import "global-search";
@import "run-query";
@import "welcome-popup";
@import "welcome-popup";
@import "oauth.wizard";

View File

@@ -0,0 +1,16 @@
.ibo-oauth-wizard .ibo-panel--body{
.ibo-oauth-wizard--form--container{
display: flex;
flex-direction: row;
flex-grow: 1;
}
.ibo-oauth-wizard--form {
}
.ibo-oauth-wizard--illustration svg{
max-height: 400px;
}
}
#ibo-oauth-wizard--conf--result{
white-space: pre-wrap
}

View File

@@ -40,20 +40,20 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:UserLocal/Attribute:password+' => '用于验证用户身份的字符串',
'Class:UserLocal/Attribute:expiration' => '密码过期',
'Class:UserLocal/Attribute:expiration+' => '密码过期状态 (需要一个扩展才能生效)',
'Class:UserLocal/Attribute:expiration+' => '密码过期状态(需要一个扩展才能生效)',
'Class:UserLocal/Attribute:expiration/Value:can_expire' => '允许过期',
'Class:UserLocal/Attribute:expiration/Value:can_expire+' => '',
'Class:UserLocal/Attribute:expiration/Value:never_expire' => '永不过期',
'Class:UserLocal/Attribute:expiration/Value:never_expire+' => '',
'Class:UserLocal/Attribute:expiration/Value:force_expire' => '已过期',
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '',
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~',
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => '一次性密码',
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => '用户不允许修改密码.',
'Class:UserLocal/Attribute:password_renewed_date' => '密码更新',
'Class:UserLocal/Attribute:password_renewed_date+' => '上次修改密码的时间',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => '密码必须至少8 个字符,包含大小写数字和特殊字符.',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => '密码必须至少8个字符,包含大小写,数字和特殊字符.',
'UserLocal:password:expiration' => '下面的区域需要插件扩展',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => '不允许用户为自己设置"一次性密码"的失效期限',
));

File diff suppressed because one or more lines are too long

View File

@@ -23,23 +23,23 @@
// Database inconsistencies
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
// Dictionary entries go here
'Menu:DBToolsMenu' => 'DB 工具',
'DBTools:Class' => 'Class~~',
'Menu:DBToolsMenu' => '数据库工具',
'DBTools:Class' => '',
'DBTools:Title' => '数据库维护工具',
'DBTools:ErrorsFound' => '发现错误',
'DBTools:Indication' => 'Important: after fixing errors in the database you\'ll have to run the analysis again as new inconsistencies will be generated~~',
'DBTools:Disclaimer' => 'DISCLAIMER: BACKUP YOUR DATABASE BEFORE RUNNING THE FIXES~~',
'DBTools:Indication' => '重要: 修复数据库错误后,可能会出现新的不一致,您必须重新运行一次分析.',
'DBTools:Disclaimer' => '免责申明: 在应用修复之前,应先备份数据库',
'DBTools:Error' => '错误',
'DBTools:Count' => '个数',
'DBTools:SQLquery' => 'SQL 查询',
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
'DBTools:SQLresult' => 'SQL 结果',
'DBTools:NoError' => '数据库OK ',
'DBTools:NoError' => '数据库正确',
'DBTools:HideIds' => '错误列表',
'DBTools:ShowIds' => '详细视图',
'DBTools:ShowReport' => '报告',
'DBTools:IntegrityCheck' => '完整性检查',
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
'DBTools:FetchCheck' => '提取检查(耗时长)',
'DBTools:SelectAnalysisType' => '请选择分析类型',
'DBTools:Analyze' => '分析',
@@ -47,17 +47,17 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'DBTools:ShowAll' => '显示所有错误',
'DBTools:Inconsistencies' => '数据库不一致',
'DBTools:DetailedErrorTitle' => '%2$s error(s) in class %1$s: %3$s~~',
'DBTools:DetailedErrorTitle' => '%2$s 个错误在类 %1$s: %3$s',
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
'DBAnalyzer-Integrity-InvalidExtKey' => '无效的外键 %1$s (列: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-MissingExtKey' => '外键丢失 %1$s (列: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-InvalidValue' => '无效的值 %1$s (列: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
'DBAnalyzer-Integrity-HKInvalid' => 'Broken hierarchical key `%1$s`~~',
'DBAnalyzer-Integrity-UsersWithoutProfile' => '一些用户账号没有角色',
'DBAnalyzer-Integrity-HKInvalid' => '损坏的层级链 `%1$s`',
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
'DBAnalyzer-Integrity-FinalClass' => 'Field `%2$s`.`%1$s` must have the same value than `%3$s`.`%1$s`~~',
'DBAnalyzer-Integrity-RootFinalClass' => 'Field `%2$s`.`%1$s` must contains a valid class~~',
'DBAnalyzer-Integrity-FinalClass' => '字段 `%2$s`.`%1$s` 必须是相同的值,而不是 `%3$s`.`%1$s`',
'DBAnalyzer-Integrity-RootFinalClass' => '字段 `%2$s`.`%1$s` 必须包含一个有效的类',
));
// Database Info
@@ -70,11 +70,11 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
// Lost attachments
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'DBTools:LostAttachments' => '缺失附件',
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
'DBTools:LostAttachments:Disclaimer' => '可以在此搜索数据库中丢失或错放的附件.这不是数据恢复工具,其无法恢复已删除的数据.',
'DBTools:LostAttachments:Button:Analyze' => '分析',
'DBTools:LostAttachments:Button:Restore' => '还原',
'DBTools:LostAttachments:Button:Restore:Confirm' => '操作无法回退, 请确认是否继续还原.',
'DBTools:LostAttachments:Button:Restore:Confirm' => '操作无法回退, 请确认是否继续还原.',
'DBTools:LostAttachments:Button:Busy' => '请稍后...',
'DBTools:LostAttachments:Step:Analyze' => '首先, 通过分析数据库来搜索丢失或误挪动的附件.',
@@ -89,6 +89,6 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'DBTools:LostAttachments:Step:RestoreResults' => '还原结果:',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d 的附件被还原.',
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
'DBTools:LostAttachments:History' => '附件 "%1$s" restored with DB 工具~~'
'DBTools:LostAttachments:StoredAsInlineImage' => '存储为内嵌图像',
'DBTools:LostAttachments:History' => '附件 "%1$s" 已使用数据库工具还原'
));

View File

@@ -21,6 +21,7 @@
<module>combodo-db-tools</module>
<module>itop-core-update</module>
<module>itop-hub-connector</module>
<module>itop-oauth-client</module>
<module>combodo-backoffice-darkmoon-theme</module>
<module>itop-themes-compat</module>
</modules>

View File

@@ -29,9 +29,9 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Attachment:Max_Mo' => '(最大文件尺寸: %1$s MB)',
'Attachment:Max_Ko' => '(最大文件尺寸: %1$s KB)',
'Attachments:NoAttachment' => '没有附件. ',
'Attachments:PreviewNotAvailable' => '附件类型不支持预览.',
'Attachments:PreviewNotAvailable' => '附件类型不支持预览.',
'Attachments:Error:FileTooLarge' => '上传的文件过大. %1$s',
'Attachments:Error:UploadedFileEmpty' => '收到的文件为空无法添加. 可能是因为您发送的是空文件,或者咨询 '.ITOP_APPLICATION_SHORT.' 管理员服务器磁盘是否已满. ',
'Attachments:Error:UploadedFileEmpty' => '收到的文件为空,无法添加. 可能是因为您发送的是空文件,或者咨询 '.ITOP_APPLICATION_SHORT.' 管理员服务器磁盘是否已满. ',
'Attachments:Render:Icons' => '显示为图标',
'Attachments:Render:Table' => '显示为列表',
'UI:Attachments:DropYourFileHint' => '将文件拖放到此区域的任意位置',
@@ -48,11 +48,11 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Attachment/Attribute:expire+' => '~~',
'Class:Attachment/Attribute:temp_id' => '临时id',
'Class:Attachment/Attribute:temp_id+' => '~~',
'Class:Attachment/Attribute:item_class' => 'Item class~~',
'Class:Attachment/Attribute:item_class' => '项目类',
'Class:Attachment/Attribute:item_class+' => '~~',
'Class:Attachment/Attribute:item_id' => '项目',
'Class:Attachment/Attribute:item_id+' => '~~',
'Class:Attachment/Attribute:item_org_id' => 'Item 组织~~',
'Class:Attachment/Attribute:item_org_id' => '项目组织',
'Class:Attachment/Attribute:item_org_id+' => '',
'Class:Attachment/Attribute:contents' => '内容',
'Class:Attachment/Attribute:contents+' => '',
@@ -74,8 +74,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Attachment/Attribute:creation_date' => '创建日期',
'Class:Attachment/Attribute:creation_date+' => '~~',
'Class:Attachment/Attribute:user_id' => '用户 id',
'Class:Attachment/Attribute:user_id' => '用户id',
'Class:Attachment/Attribute:user_id+' => '~~',
'Class:Attachment/Attribute:contact_id' => '联系人 id',
'Class:Attachment/Attribute:contact_id' => '联系人id',
'Class:Attachment/Attribute:contact_id+' => '~~',
));

View File

@@ -28,14 +28,14 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Menu:BackupStatus' => '定时备份',
'bkp-status-title' => '定时备份',
'bkp-status-checks' => '设置与检查',
'bkp-mysqldump-ok' => '已找到 mysqldump : %1$s',
'bkp-mysqldump-ok' => '已找到mysqldump : %1$s',
'bkp-mysqldump-notfound' => 'mysqldump 找不到: %1$s - 请确认它安装在正确的路径, 或者调整'.ITOP_APPLICATION_SHORT.' 配置文件的选项mysql_bindir.',
'bkp-mysqldump-issue' => 'mysqldump 无法运行 (retcode=%1$d): 请确认它安装在正确的路径, 或者调整'.ITOP_APPLICATION_SHORT.' 配置文件的选项mysql_bindir',
'bkp-missing-dir' => '目标目录 <code>%1$s</code> 找不到',
'bkp-free-disk-space' => '<b>%1$s 空闲</b> <code>%2$s</code>',
'bkp-free-disk-space' => '<b>%1$s 可用空间 </b> 位于 <code>%2$s</code>',
'bkp-dir-not-writeable' => '%1$s 没有写入权限',
'bkp-wrong-format-spec' => '当前文件名格式错误 (%1$s). 默认格式应该是: %2$s',
'bkp-name-sample' => '备份文件将以数据库名日期和时间进行命名. 例如: %1$s',
'bkp-name-sample' => '备份文件将以数据库名,日期和时间进行命名. 例如: %1$s',
'bkp-week-days' => '在每个 <b> %1$s 的 %2$s</b> 进行备份',
'bkp-retention' => '最多 <b>%1$d 份备份文件 </b> 在目标目录.',
'bkp-next-to-delete' => '当下一次备份时将被删除 (see the setting "retention_count")',
@@ -49,7 +49,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'bkp-status-backups-manual' => '手动备份',
'bkp-status-backups-none' => '尚未开始备份',
'bkp-next-backup' => '下一次备份将发生在 <b>%1$s</b> (%2$s) 的 %3$s',
'bkp-next-backup-unknown' => 'The next backup is <b>not scheduled</b> yet.~~',
'bkp-next-backup-unknown' => '下一次备份<b>尚未被计划</b>.',
'bkp-button-backup-now' => '立即备份!',
'bkp-button-restore-now' => '还原!',
'bkp-confirm-backup' => '请确认是否立即开始备份.',

View File

@@ -91,9 +91,9 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:FunctionalCI/Attribute:providercontracts_list' => '供应商合同',
'Class:FunctionalCI/Attribute:providercontracts_list+' => '配置项的所有供应商合同',
'Class:FunctionalCI/Attribute:providercontracts_list+' => '配置项的所有供应商合同',
'Class:FunctionalCI/Attribute:services_list' => '服务',
'Class:FunctionalCI/Attribute:services_list+' => '配置项影响的所有服务',
'Class:FunctionalCI/Attribute:services_list+' => '配置项影响的所有服务',
'Class:FunctionalCI/Attribute:tickets_list' => '工单',
'Class:FunctionalCI/Attribute:tickets_list+' => '配置项包含的所有工单',
'Class:FunctionalCI/Attribute:tickets_list+' => '配置项包含的所有工单',
));

View File

@@ -125,13 +125,13 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Change/Attribute:parent_name' => '变更编号',
'Class:Change/Attribute:parent_name+' => '',
'Class:Change/Attribute:related_request_list' => '相关需求',
'Class:Change/Attribute:related_request_list+' => '变更相关的所有用户需求',
'Class:Change/Attribute:related_request_list+' => '变更相关的所有用户需求',
'Class:Change/Attribute:related_problems_list' => '相关问题',
'Class:Change/Attribute:related_problems_list+' => '变更相关的所有问题',
'Class:Change/Attribute:related_problems_list+' => '变更相关的所有问题',
'Class:Change/Attribute:related_incident_list' => '相关事件',
'Class:Change/Attribute:related_incident_list+' => '变更相关的所有事件',
'Class:Change/Attribute:related_incident_list+' => '变更相关的所有事件',
'Class:Change/Attribute:child_changes_list' => '子变更',
'Class:Change/Attribute:child_changes_list+' => '变更相关的字变更',
'Class:Change/Attribute:child_changes_list+' => '变更相关的字变更',
'Class:Change/Attribute:parent_id_friendlyname' => '父级变更昵称',
'Class:Change/Attribute:parent_id_friendlyname+' => '',
'Class:Change/Attribute:parent_id_finalclass_recall' => '变更类型',

View File

@@ -109,13 +109,13 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Change/Attribute:fallback_plan' => '回滚计划',
'Class:Change/Attribute:fallback_plan+' => '',
'Class:Change/Attribute:related_request_list' => '相关需求',
'Class:Change/Attribute:related_request_list+' => '变更相关的所有用户需求',
'Class:Change/Attribute:related_request_list+' => '变更相关的所有用户需求',
'Class:Change/Attribute:related_incident_list' => '相关事件',
'Class:Change/Attribute:related_incident_list+' => '变更相关的所有事件',
'Class:Change/Attribute:related_incident_list+' => '变更相关的所有事件',
'Class:Change/Attribute:related_problems_list' => '相关问题',
'Class:Change/Attribute:related_problems_list+' => '变更相关的所有问题',
'Class:Change/Attribute:related_problems_list+' => '变更相关的所有问题',
'Class:Change/Attribute:child_changes_list' => '子变更',
'Class:Change/Attribute:child_changes_list+' => '变更相关的所有子变更',
'Class:Change/Attribute:child_changes_list+' => '变更相关的所有子变更',
'Class:Change/Attribute:parent_id_friendlyname' => '父级变更昵称',
'Class:Change/Attribute:parent_id_friendlyname+' => '',
'Class:Change/Stimulus:ev_assign' => '分配',

View File

@@ -29,12 +29,12 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Relation:impacts/DownStream' => '影响...',
'Relation:impacts/DownStream+' => '被影响的元素',
'Relation:impacts/UpStream' => '依赖于...',
'Relation:impacts/UpStream+' => '元素依赖的元素...',
'Relation:impacts/UpStream+' => '元素依赖的元素...',
// Legacy entries
'Relation:depends on/Description' => '元素依赖的元素...',
'Relation:depends on/Description' => '元素依赖的元素...',
'Relation:depends on/DownStream' => '依赖于...',
'Relation:depends on/UpStream' => '影响...',
'Relation:impacts/LoadData' => 'Load data~~',
'Relation:impacts/LoadData' => '加载数据',
'Relation:impacts/NoFilteredData' => 'please select objects in Graphical view tag~~',
));
@@ -81,7 +81,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:lnkContactToFunctionalCI' => '链接 联系人 / 功能项',
'Class:lnkContactToFunctionalCI' => '关联 联系人/功能项',
'Class:lnkContactToFunctionalCI+' => '',
'Class:lnkContactToFunctionalCI/Attribute:functionalci_id' => '功能项',
'Class:lnkContactToFunctionalCI/Attribute:functionalci_id+' => '',
@@ -119,13 +119,13 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:FunctionalCI/Attribute:move2production' => '投产日期',
'Class:FunctionalCI/Attribute:move2production+' => '',
'Class:FunctionalCI/Attribute:contacts_list' => '联系人',
'Class:FunctionalCI/Attribute:contacts_list+' => '配置项的所有联系人',
'Class:FunctionalCI/Attribute:contacts_list+' => '配置项的所有联系人',
'Class:FunctionalCI/Attribute:documents_list' => '文档',
'Class:FunctionalCI/Attribute:documents_list+' => '配置项关联的所有文档',
'Class:FunctionalCI/Attribute:documents_list+' => '配置项关联的所有文档',
'Class:FunctionalCI/Attribute:applicationsolution_list' => '应用方案',
'Class:FunctionalCI/Attribute:applicationsolution_list+' => '配置项依赖的所有应用方案',
'Class:FunctionalCI/Attribute:applicationsolution_list+' => '配置项依赖的所有应用方案',
'Class:FunctionalCI/Attribute:softwares_list' => '软件',
'Class:FunctionalCI/Attribute:softwares_list+' => '配置项上已安装的所有软件',
'Class:FunctionalCI/Attribute:softwares_list+' => '配置项上已安装的所有软件',
'Class:FunctionalCI/Attribute:finalclass' => '二级配置项',
'Class:FunctionalCI/Attribute:finalclass+' => 'Name of the final class',
'Class:FunctionalCI/Tab:OpenedTickets' => '活跃的工单',
@@ -180,9 +180,9 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Rack/Attribute:nb_u' => '机柜高度',
'Class:Rack/Attribute:nb_u+' => '',
'Class:Rack/Attribute:device_list' => '设备',
'Class:Rack/Attribute:device_list+' => '机柜托管的所有物理设备',
'Class:Rack/Attribute:device_list+' => '机柜托管的所有物理设备',
'Class:Rack/Attribute:enclosure_list' => '机位',
'Class:Rack/Attribute:enclosure_list+' => '机柜上的所有机位',
'Class:Rack/Attribute:enclosure_list+' => '机柜上的所有机位',
));
//
@@ -190,7 +190,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:TelephonyCI' => 'Telephony CI',
'Class:TelephonyCI' => '电讯配置项',
'Class:TelephonyCI+' => '',
'Class:TelephonyCI/Attribute:phonenumber' => '电话号码',
'Class:TelephonyCI/Attribute:phonenumber+' => '',
@@ -270,20 +270,20 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:DatacenterDevice/Attribute:managementip+' => '',
'Class:DatacenterDevice/Attribute:powerA_id' => '电源A',
'Class:DatacenterDevice/Attribute:powerA_id+' => '',
'Class:DatacenterDevice/Attribute:powerA_name' => 'PowerA source name',
'Class:DatacenterDevice/Attribute:powerA_name' => '电源A名称',
'Class:DatacenterDevice/Attribute:powerA_name+' => '',
'Class:DatacenterDevice/Attribute:powerB_id' => '电源B',
'Class:DatacenterDevice/Attribute:powerB_id+' => '',
'Class:DatacenterDevice/Attribute:powerB_name' => 'PowerB source name',
'Class:DatacenterDevice/Attribute:powerB_name' => '电源B名称',
'Class:DatacenterDevice/Attribute:powerB_name+' => '',
'Class:DatacenterDevice/Attribute:fiberinterfacelist_list' => '光纤端口',
'Class:DatacenterDevice/Attribute:fiberinterfacelist_list+' => '设备的所有光纤端口',
'Class:DatacenterDevice/Attribute:fiberinterfacelist_list+' => '设备的所有光纤端口',
'Class:DatacenterDevice/Attribute:san_list' => 'SANs',
'Class:DatacenterDevice/Attribute:san_list+' => '所有连接到这台设备的SAN 交换机',
'Class:DatacenterDevice/Attribute:san_list+' => '所有连接到这台设备的SAN交换机',
'Class:DatacenterDevice/Attribute:redundancy' => '冗余',
'Class:DatacenterDevice/Attribute:redundancy/count' => '设备运行正常至少需要一路电源 (A 或 B)',
'Class:DatacenterDevice/Attribute:redundancy/count' => '设备运行正常至少需要一路电源 (A 或 B)',
// Unused yet
'Class:DatacenterDevice/Attribute:redundancy/disabled' => '所有电源正常,设备才正常',
'Class:DatacenterDevice/Attribute:redundancy/disabled' => '所有电源正常,设备才正常',
'Class:DatacenterDevice/Attribute:redundancy/percent' => '至少 %1$s %% 路电源正常,设备才正常',
));
@@ -299,10 +299,10 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:NetworkDevice/Attribute:networkdevicetype_name' => '网络设备类型名称',
'Class:NetworkDevice/Attribute:networkdevicetype_name+' => '',
'Class:NetworkDevice/Attribute:connectablecis_list' => '设备',
'Class:NetworkDevice/Attribute:connectablecis_list+' => '连接到网络设备的所有设备',
'Class:NetworkDevice/Attribute:iosversion_id' => 'IOS 版本',
'Class:NetworkDevice/Attribute:connectablecis_list+' => '连接到网络设备的所有设备',
'Class:NetworkDevice/Attribute:iosversion_id' => 'IOS版本',
'Class:NetworkDevice/Attribute:iosversion_id+' => '',
'Class:NetworkDevice/Attribute:iosversion_name' => 'IOS 版本名称',
'Class:NetworkDevice/Attribute:iosversion_name' => 'IOS版本名称',
'Class:NetworkDevice/Attribute:iosversion_name+' => '',
'Class:NetworkDevice/Attribute:ram' => '内存',
'Class:NetworkDevice/Attribute:ram+' => '',
@@ -332,7 +332,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Server/Attribute:ram' => '内存',
'Class:Server/Attribute:ram+' => '',
'Class:Server/Attribute:logicalvolumes_list' => '逻辑卷',
'Class:Server/Attribute:logicalvolumes_list+' => '连接到服务器的所有逻辑卷',
'Class:Server/Attribute:logicalvolumes_list+' => '连接到服务器的所有逻辑卷',
));
//
@@ -343,7 +343,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:StorageSystem' => '存储系统',
'Class:StorageSystem+' => '',
'Class:StorageSystem/Attribute:logicalvolume_list' => '逻辑卷',
'Class:StorageSystem/Attribute:logicalvolume_list+' => '存储系统包含的所有逻辑卷',
'Class:StorageSystem/Attribute:logicalvolume_list+' => '存储系统包含的所有逻辑卷',
));
//
@@ -351,10 +351,10 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:SANSwitch' => 'SAN 交换机',
'Class:SANSwitch' => 'SAN交换机',
'Class:SANSwitch+' => '',
'Class:SANSwitch/Attribute:datacenterdevice_list' => '设备',
'Class:SANSwitch/Attribute:datacenterdevice_list+' => '连接到SAN 交换机的所有设备',
'Class:SANSwitch/Attribute:datacenterdevice_list+' => '连接到SAN交换机的所有设备',
));
//
@@ -365,7 +365,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:TapeLibrary' => '磁带库',
'Class:TapeLibrary+' => '',
'Class:TapeLibrary/Attribute:tapes_list' => '磁带',
'Class:TapeLibrary/Attribute:tapes_list+' => '磁带库里的所有磁带',
'Class:TapeLibrary/Attribute:tapes_list+' => '磁带库里的所有磁带',
));
//
@@ -376,7 +376,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:NAS' => 'NAS',
'Class:NAS+' => '',
'Class:NAS/Attribute:nasfilesystem_list' => '文件系统',
'Class:NAS/Attribute:nasfilesystem_list+' => 'NAS 里的所有文件系统',
'Class:NAS/Attribute:nasfilesystem_list+' => 'NAS里的所有文件系统',
));
//
@@ -432,7 +432,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:PowerSource' => '电源',
'Class:PowerSource+' => '',
'Class:PowerSource/Attribute:pdus_list' => 'PDU',
'Class:PowerSource/Attribute:pdus_list+' => '使用电源的所有PDU',
'Class:PowerSource/Attribute:pdus_list+' => '使用电源的所有PDU',
));
//
@@ -475,7 +475,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Enclosure/Attribute:nb_u' => '高度',
'Class:Enclosure/Attribute:nb_u+' => '',
'Class:Enclosure/Attribute:device_list' => '设备',
'Class:Enclosure/Attribute:device_list+' => '机位的所有设备',
'Class:Enclosure/Attribute:device_list+' => '机位的所有设备',
));
//
@@ -486,9 +486,9 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:ApplicationSolution' => '应用方案',
'Class:ApplicationSolution+' => '',
'Class:ApplicationSolution/Attribute:functionalcis_list' => '配置项',
'Class:ApplicationSolution/Attribute:functionalcis_list+' => '应用方案包含的所有配置项',
'Class:ApplicationSolution/Attribute:functionalcis_list+' => '应用方案包含的所有配置项',
'Class:ApplicationSolution/Attribute:businessprocess_list' => '业务流程',
'Class:ApplicationSolution/Attribute:businessprocess_list+' => '所有依赖应用方案的业务流程',
'Class:ApplicationSolution/Attribute:businessprocess_list+' => '所有依赖应用方案的业务流程',
'Class:ApplicationSolution/Attribute:status' => '状态',
'Class:ApplicationSolution/Attribute:status+' => '',
'Class:ApplicationSolution/Attribute:status/Value:active' => '启用',
@@ -496,9 +496,9 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:ApplicationSolution/Attribute:status/Value:inactive' => '停用',
'Class:ApplicationSolution/Attribute:status/Value:inactive+' => '停用',
'Class:ApplicationSolution/Attribute:redundancy' => '影响分析: 冗余配置',
'Class:ApplicationSolution/Attribute:redundancy/disabled' => 'The solution is up if all CIs are up',
'Class:ApplicationSolution/Attribute:redundancy/count' => 'The solution is up if at least %1$s CI(s) is(are) up',
'Class:ApplicationSolution/Attribute:redundancy/percent' => 'The solution is up if at least %1$s %% of the CIs are up',
'Class:ApplicationSolution/Attribute:redundancy/disabled' => '所有配置项正常,此应用方案才正常',
'Class:ApplicationSolution/Attribute:redundancy/count' => '至少 %1$s 个配置项正常时此应用方案才正常',
'Class:ApplicationSolution/Attribute:redundancy/percent' => '至少 %1$s %% 的配置项正常,此应用方案才正常',
));
//
@@ -509,7 +509,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:BusinessProcess' => '业务流程',
'Class:BusinessProcess+' => '',
'Class:BusinessProcess/Attribute:applicationsolutions_list' => '应用方案',
'Class:BusinessProcess/Attribute:applicationsolutions_list+' => '所有影响业务流程的应用方案',
'Class:BusinessProcess/Attribute:applicationsolutions_list+' => '所有影响业务流程的应用方案',
'Class:BusinessProcess/Attribute:status' => '状态',
'Class:BusinessProcess/Attribute:status+' => '',
'Class:BusinessProcess/Attribute:status/Value:active' => '启用',
@@ -555,7 +555,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Middleware' => '中间件',
'Class:Middleware+' => '',
'Class:Middleware/Attribute:middlewareinstance_list' => '中间件实例',
'Class:Middleware/Attribute:middlewareinstance_list+' => '中间件的所有实例',
'Class:Middleware/Attribute:middlewareinstance_list+' => '中间件的所有实例',
));
//
@@ -566,7 +566,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:DBServer' => '数据库服务器',
'Class:DBServer+' => '',
'Class:DBServer/Attribute:dbschema_list' => '数据库',
'Class:DBServer/Attribute:dbschema_list+' => '数据库服务器上的所有数据库架构',
'Class:DBServer/Attribute:dbschema_list+' => '数据库服务器上的所有数据库架构',
));
//
@@ -577,7 +577,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:WebServer' => 'Web 服务器',
'Class:WebServer+' => '',
'Class:WebServer/Attribute:webapp_list' => 'Web 应用',
'Class:WebServer/Attribute:webapp_list+' => 'web 服务器上的所有web 应用',
'Class:WebServer/Attribute:webapp_list+' => 'web 服务器上的所有web 应用',
));
//
@@ -658,7 +658,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:VirtualDevice/Attribute:status/Value:stock' => '库存',
'Class:VirtualDevice/Attribute:status/Value:stock+' => '库存',
'Class:VirtualDevice/Attribute:logicalvolumes_list' => '逻辑卷',
'Class:VirtualDevice/Attribute:logicalvolumes_list+' => '设备使用的所有逻辑卷',
'Class:VirtualDevice/Attribute:logicalvolumes_list+' => '设备使用的所有逻辑卷',
));
//
@@ -669,7 +669,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:VirtualHost' => '宿主机',
'Class:VirtualHost+' => '',
'Class:VirtualHost/Attribute:virtualmachine_list' => '虚拟机',
'Class:VirtualHost/Attribute:virtualmachine_list+' => '宿主机托管的所有虚拟机',
'Class:VirtualHost/Attribute:virtualmachine_list+' => '宿主机托管的所有虚拟机',
));
//
@@ -759,9 +759,9 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:LogicalVolume/Attribute:storagesystem_name' => '名称',
'Class:LogicalVolume/Attribute:storagesystem_name+' => '',
'Class:LogicalVolume/Attribute:servers_list' => '服务器',
'Class:LogicalVolume/Attribute:servers_list+' => '使用逻辑卷的服务器',
'Class:LogicalVolume/Attribute:servers_list+' => '使用逻辑卷的服务器',
'Class:LogicalVolume/Attribute:virtualdevices_list' => '虚拟设备',
'Class:LogicalVolume/Attribute:virtualdevices_list+' => '使用逻辑卷的所有虚拟设备',
'Class:LogicalVolume/Attribute:virtualdevices_list+' => '使用逻辑卷的所有虚拟设备',
));
//
@@ -769,7 +769,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:lnkServerToVolume' => '链接 服务器 / 逻辑卷',
'Class:lnkServerToVolume' => '关联 服务器/逻辑卷',
'Class:lnkServerToVolume+' => '',
'Class:lnkServerToVolume/Attribute:volume_id' => '逻辑卷',
'Class:lnkServerToVolume/Attribute:volume_id+' => '',
@@ -788,7 +788,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:lnkVirtualDeviceToVolume' => '链接 虚拟设备 / 逻辑卷',
'Class:lnkVirtualDeviceToVolume' => '关联 虚拟设备/逻辑卷',
'Class:lnkVirtualDeviceToVolume+' => '',
'Class:lnkVirtualDeviceToVolume/Attribute:volume_id' => '逻辑卷',
'Class:lnkVirtualDeviceToVolume/Attribute:volume_id+' => '',
@@ -807,7 +807,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:lnkSanToDatacenterDevice' => '链接 SAN / 数据中心设备',
'Class:lnkSanToDatacenterDevice' => '关联 SAN/数据中心设备',
'Class:lnkSanToDatacenterDevice+' => '',
'Class:lnkSanToDatacenterDevice/Attribute:san_id' => 'SAN 交换机',
'Class:lnkSanToDatacenterDevice/Attribute:san_id+' => '',
@@ -877,7 +877,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Software/Attribute:version' => '版本',
'Class:Software/Attribute:version+' => '',
'Class:Software/Attribute:documents_list' => '文档',
'Class:Software/Attribute:documents_list+' => '软件的所有文档',
'Class:Software/Attribute:documents_list+' => '软件的所有文档',
'Class:Software/Attribute:type' => '类型',
'Class:Software/Attribute:type+' => '',
'Class:Software/Attribute:type/Value:DBServer' => '数据库服务器',
@@ -891,11 +891,11 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Software/Attribute:type/Value:WebServer' => 'Web 服务器',
'Class:Software/Attribute:type/Value:WebServer+' => 'Web 服务器',
'Class:Software/Attribute:softwareinstance_list' => '软件实例',
'Class:Software/Attribute:softwareinstance_list+' => '软件的所有实例',
'Class:Software/Attribute:softwareinstance_list+' => '软件的所有实例',
'Class:Software/Attribute:softwarepatch_list' => '软件补丁',
'Class:Software/Attribute:softwarepatch_list+' => '软件的所有补丁',
'Class:Software/Attribute:softwarepatch_list+' => '软件的所有补丁',
'Class:Software/Attribute:softwarelicence_list' => '软件许可证',
'Class:Software/Attribute:softwarelicence_list+' => '软件的所有许可证',
'Class:Software/Attribute:softwarelicence_list+' => '软件的所有许可证',
));
//
@@ -908,7 +908,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Patch/Attribute:name' => '名称',
'Class:Patch/Attribute:name+' => '',
'Class:Patch/Attribute:documents_list' => '文档',
'Class:Patch/Attribute:documents_list+' => '补丁关联的所有文档',
'Class:Patch/Attribute:documents_list+' => '补丁关联的所有文档',
'Class:Patch/Attribute:description' => '描述',
'Class:Patch/Attribute:description+' => '',
'Class:Patch/Attribute:finalclass' => '补丁子类别',
@@ -923,7 +923,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:OSPatch' => '操作系统补丁',
'Class:OSPatch+' => '',
'Class:OSPatch/Attribute:functionalcis_list' => '设备',
'Class:OSPatch/Attribute:functionalcis_list+' => '已安装补丁的所有系统',
'Class:OSPatch/Attribute:functionalcis_list+' => '已安装补丁的所有系统',
'Class:OSPatch/Attribute:osversion_id' => '操作系统版本',
'Class:OSPatch/Attribute:osversion_id+' => '',
'Class:OSPatch/Attribute:osversion_name' => '名称',
@@ -942,7 +942,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:SoftwarePatch/Attribute:software_name' => '名称',
'Class:SoftwarePatch/Attribute:software_name+' => '',
'Class:SoftwarePatch/Attribute:softwareinstances_list' => '软件实例',
'Class:SoftwarePatch/Attribute:softwareinstances_list+' => '已安装软件补丁的所有系统',
'Class:SoftwarePatch/Attribute:softwareinstances_list+' => '已安装软件补丁的所有系统',
));
//
@@ -955,7 +955,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Licence/Attribute:name' => '名称',
'Class:Licence/Attribute:name+' => '',
'Class:Licence/Attribute:documents_list' => '文档',
'Class:Licence/Attribute:documents_list+' => '许可证关联的所有文档',
'Class:Licence/Attribute:documents_list+' => '许可证关联的所有文档',
'Class:Licence/Attribute:org_id' => '组织',
'Class:Licence/Attribute:org_id+' => '',
'Class:Licence/Attribute:organization_name' => '组织名称',
@@ -992,9 +992,9 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:OSLicence/Attribute:osversion_name' => '名称',
'Class:OSLicence/Attribute:osversion_name+' => '',
'Class:OSLicence/Attribute:virtualmachines_list' => '虚拟机',
'Class:OSLicence/Attribute:virtualmachines_list+' => '使用许可证的所有虚拟机',
'Class:OSLicence/Attribute:virtualmachines_list+' => '使用许可证的所有虚拟机',
'Class:OSLicence/Attribute:servers_list' => '服务器',
'Class:OSLicence/Attribute:servers_list+' => '使用许可证的所有服务器',
'Class:OSLicence/Attribute:servers_list+' => '使用许可证的所有服务器',
));
//
@@ -1009,7 +1009,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:SoftwareLicence/Attribute:software_name' => '名称',
'Class:SoftwareLicence/Attribute:software_name+' => '',
'Class:SoftwareLicence/Attribute:softwareinstance_list' => '软件实例',
'Class:SoftwareLicence/Attribute:softwareinstance_list+' => '使用许可证的所有系统',
'Class:SoftwareLicence/Attribute:softwareinstance_list+' => '使用许可证的所有系统',
));
//
@@ -1017,7 +1017,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:lnkDocumentToLicence' => '链接 文档 / 许可证',
'Class:lnkDocumentToLicence' => '关联 文档/许可证',
'Class:lnkDocumentToLicence+' => '',
'Class:lnkDocumentToLicence/Attribute:licence_id' => '许可证',
'Class:lnkDocumentToLicence/Attribute:licence_id+' => '',
@@ -1059,9 +1059,9 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Brand' => '品牌',
'Class:Brand+' => '',
'Class:Brand/Attribute:physicaldevices_list' => '物理设备',
'Class:Brand/Attribute:physicaldevices_list+' => '品牌的所有物理设备',
'Class:Brand/Attribute:physicaldevices_list+' => '品牌的所有物理设备',
'Class:Brand/UniquenessRule:name+' => '名称必须唯一',
'Class:Brand/UniquenessRule:name' => '品牌已存在',
'Class:Brand/UniquenessRule:name' => '品牌已存在',
));
//
@@ -1083,8 +1083,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Model/Attribute:type/Value:DiskArray+' => '磁盘阵列',
'Class:Model/Attribute:type/Value:Enclosure' => '机位',
'Class:Model/Attribute:type/Value:Enclosure+' => '机位',
'Class:Model/Attribute:type/Value:IPPhone' => 'IP 电话',
'Class:Model/Attribute:type/Value:IPPhone+' => 'IP 电话',
'Class:Model/Attribute:type/Value:IPPhone' => 'IP电话',
'Class:Model/Attribute:type/Value:IPPhone+' => 'IP电话',
'Class:Model/Attribute:type/Value:MobilePhone' => '移动电话',
'Class:Model/Attribute:type/Value:MobilePhone+' => '移动电话',
'Class:Model/Attribute:type/Value:NAS' => 'NAS',
@@ -1101,10 +1101,10 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Model/Attribute:type/Value:Printer+' => '打印机',
'Class:Model/Attribute:type/Value:Rack' => '机柜',
'Class:Model/Attribute:type/Value:Rack+' => '机柜',
'Class:Model/Attribute:type/Value:SANSwitch' => 'SAN 交换机',
'Class:Model/Attribute:type/Value:SANSwitch+' => 'SAN 交换机',
'Class:Model/Attribute:type/Value:SANSwitch' => 'SAN交换机',
'Class:Model/Attribute:type/Value:SANSwitch+' => 'SAN交换机',
'Class:Model/Attribute:type/Value:Server' => '服务器',
'Class:Model/Attribute:type/Value:Server+' => 'Server',
'Class:Model/Attribute:type/Value:Server+' => '服务器',
'Class:Model/Attribute:type/Value:StorageSystem' => '存储系统',
'Class:Model/Attribute:type/Value:StorageSystem+' => '存储系统',
'Class:Model/Attribute:type/Value:Tablet' => '平板',
@@ -1114,9 +1114,9 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Model/Attribute:type/Value:Phone' => '电话',
'Class:Model/Attribute:type/Value:Phone+' => '电话',
'Class:Model/Attribute:physicaldevices_list' => '物理设备',
'Class:Model/Attribute:physicaldevices_list+' => '型号的所有物理设备',
'Class:Model/Attribute:physicaldevices_list+' => '型号的所有物理设备',
'Class:Model/UniquenessRule:name_brand+' => '名称必须唯一',
'Class:Model/UniquenessRule:name_brand' => '型号已存在',
'Class:Model/UniquenessRule:name_brand' => '型号已存在',
));
//
@@ -1127,7 +1127,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:NetworkDeviceType' => '网络设备类型',
'Class:NetworkDeviceType+' => '',
'Class:NetworkDeviceType/Attribute:networkdevicesdevices_list' => '网络设备',
'Class:NetworkDeviceType/Attribute:networkdevicesdevices_list+' => '类型的所有网络设备',
'Class:NetworkDeviceType/Attribute:networkdevicesdevices_list+' => '类型的所有网络设备',
));
//
@@ -1135,7 +1135,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:IOSVersion' => 'IOS 版本',
'Class:IOSVersion' => 'IOS版本',
'Class:IOSVersion+' => '',
'Class:IOSVersion/Attribute:brand_id' => '品牌',
'Class:IOSVersion/Attribute:brand_id+' => '',
@@ -1148,7 +1148,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:lnkDocumentToPatch' => '链接 文档 / 补丁',
'Class:lnkDocumentToPatch' => '关联 文档/补丁',
'Class:lnkDocumentToPatch+' => '',
'Class:lnkDocumentToPatch/Attribute:patch_id' => '补丁',
'Class:lnkDocumentToPatch/Attribute:patch_id+' => '',
@@ -1165,7 +1165,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:lnkSoftwareInstanceToSoftwarePatch' => '链接 软件实例 / 软件补丁',
'Class:lnkSoftwareInstanceToSoftwarePatch' => ' 关联 软件实例/软件补丁',
'Class:lnkSoftwareInstanceToSoftwarePatch+' => '',
'Class:lnkSoftwareInstanceToSoftwarePatch/Attribute:softwarepatch_id' => '软件补丁',
'Class:lnkSoftwareInstanceToSoftwarePatch/Attribute:softwarepatch_id+' => '',
@@ -1182,7 +1182,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:lnkFunctionalCIToOSPatch' => '链接 功能项 / 操作系统补丁',
'Class:lnkFunctionalCIToOSPatch' => '关联 功能项/操作系统补丁',
'Class:lnkFunctionalCIToOSPatch+' => '',
'Class:lnkFunctionalCIToOSPatch/Attribute:ospatch_id' => '操作系统补丁',
'Class:lnkFunctionalCIToOSPatch/Attribute:ospatch_id+' => '',
@@ -1199,7 +1199,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:lnkDocumentToSoftware' => '链接 文档 / 软件',
'Class:lnkDocumentToSoftware' => '关联 文档/软件',
'Class:lnkDocumentToSoftware+' => '',
'Class:lnkDocumentToSoftware/Attribute:software_id' => '软件',
'Class:lnkDocumentToSoftware/Attribute:software_id+' => '',
@@ -1241,7 +1241,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:VLAN' => 'VLAN',
'Class:VLAN+' => '',
'Class:VLAN/Attribute:vlan_tag' => 'VLAN 标记',
'Class:VLAN/Attribute:vlan_tag' => 'VLAN标记',
'Class:VLAN/Attribute:vlan_tag+' => '',
'Class:VLAN/Attribute:description' => '描述',
'Class:VLAN/Attribute:description+' => '',
@@ -1260,7 +1260,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:lnkSubnetToVLAN' => '链接 子网 / VLAN',
'Class:lnkSubnetToVLAN' => '关联 子网/VLAN',
'Class:lnkSubnetToVLAN+' => '',
'Class:lnkSubnetToVLAN/Attribute:subnet_id' => '子网',
'Class:lnkSubnetToVLAN/Attribute:subnet_id+' => '',
@@ -1292,13 +1292,13 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:IPInterface' => 'IP Interface',
'Class:IPInterface' => 'IP接口',
'Class:IPInterface+' => '',
'Class:IPInterface/Attribute:ipaddress' => 'IP 地址',
'Class:IPInterface/Attribute:ipaddress' => 'IP地址',
'Class:IPInterface/Attribute:ipaddress+' => '',
'Class:IPInterface/Attribute:macaddress' => 'MAC 地址',
'Class:IPInterface/Attribute:macaddress' => 'MAC地址',
'Class:IPInterface/Attribute:macaddress+' => '',
'Class:IPInterface/Attribute:comment' => '注释',
'Class:IPInterface/Attribute:coment+' => '',
@@ -1330,7 +1330,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:lnkPhysicalInterfaceToVLAN' => '链接 物理网卡 / VLAN',
'Class:lnkPhysicalInterfaceToVLAN' => '关联 物理网卡/VLAN',
'Class:lnkPhysicalInterfaceToVLAN+' => '',
'Class:lnkPhysicalInterfaceToVLAN/Attribute:physicalinterface_id' => '物理网卡',
'Class:lnkPhysicalInterfaceToVLAN/Attribute:physicalinterface_id+' => '',
@@ -1342,7 +1342,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:lnkPhysicalInterfaceToVLAN/Attribute:physicalinterface_device_name+' => '',
'Class:lnkPhysicalInterfaceToVLAN/Attribute:vlan_id' => 'VLAN',
'Class:lnkPhysicalInterfaceToVLAN/Attribute:vlan_id+' => '',
'Class:lnkPhysicalInterfaceToVLAN/Attribute:vlan_tag' => 'VLAN 标记',
'Class:lnkPhysicalInterfaceToVLAN/Attribute:vlan_tag' => 'VLAN标记',
'Class:lnkPhysicalInterfaceToVLAN/Attribute:vlan_tag+' => '',
));
@@ -1384,7 +1384,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:lnkConnectableCIToNetworkDevice' => '链接 可连接项 / 网络设备',
'Class:lnkConnectableCIToNetworkDevice' => '关联 可连接项/网络设备',
'Class:lnkConnectableCIToNetworkDevice+' => '',
'Class:lnkConnectableCIToNetworkDevice/Attribute:networkdevice_id' => '网络设备',
'Class:lnkConnectableCIToNetworkDevice/Attribute:networkdevice_id+' => '',
@@ -1411,7 +1411,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:lnkApplicationSolutionToFunctionalCI' => '链接 应用方案 / 功能项',
'Class:lnkApplicationSolutionToFunctionalCI' => '关联 应用方案/功能项',
'Class:lnkApplicationSolutionToFunctionalCI+' => '',
'Class:lnkApplicationSolutionToFunctionalCI/Attribute:applicationsolution_id' => '应用方案',
'Class:lnkApplicationSolutionToFunctionalCI/Attribute:applicationsolution_id+' => '',
@@ -1428,7 +1428,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:lnkApplicationSolutionToBusinessProcess' => '链接 应用方案 / 业务流程',
'Class:lnkApplicationSolutionToBusinessProcess' => '关联 应用方案/业务流程',
'Class:lnkApplicationSolutionToBusinessProcess+' => '',
'Class:lnkApplicationSolutionToBusinessProcess/Attribute:businessprocess_id' => '业务流程',
'Class:lnkApplicationSolutionToBusinessProcess/Attribute:businessprocess_id+' => '',
@@ -1470,8 +1470,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Group/Attribute:parent_id+' => '',
'Class:Group/Attribute:parent_name' => '名称',
'Class:Group/Attribute:parent_name+' => '',
'Class:Group/Attribute:ci_list' => '链接的配置项',
'Class:Group/Attribute:ci_list+' => '组关联的所有配置项',
'Class:Group/Attribute:ci_list' => '关联的配置项',
'Class:Group/Attribute:ci_list+' => '组关联的所有配置项',
'Class:Group/Attribute:parent_id_friendlyname' => '上级配置组',
'Class:Group/Attribute:parent_id_friendlyname+' => '',
));
@@ -1481,7 +1481,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:lnkGroupToCI' => '链接 配置组 / 配置项',
'Class:lnkGroupToCI' => '关联 配置组/配置项',
'Class:lnkGroupToCI+' => '',
'Class:lnkGroupToCI/Attribute:group_id' => '组',
'Class:lnkGroupToCI/Attribute:group_id+' => '',
@@ -1505,8 +1505,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Server:power' => '电力供应',
'Class:Subnet/Tab:IPUsage' => 'IP 使用率',
'Class:Subnet/Tab:IPUsage-explain' => '网卡IP范围: <em>%1$s</em> 到 <em>%2$s</em>',
'Class:Subnet/Tab:FreeIPs' => '空闲 IP',
'Class:Subnet/Tab:FreeIPs-count' => '空闲 IP: %1$s',
'Class:Subnet/Tab:FreeIPs' => '空闲IP',
'Class:Subnet/Tab:FreeIPs-count' => '空闲IP: %1$s',
'Class:Subnet/Tab:FreeIPs-explain' => '以下是抽取的10个空闲IP',
'Class:Document:PreviewTab' => '预览',
));
@@ -1517,7 +1517,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:lnkDocumentToFunctionalCI' => '链接 文档 / 功能项',
'Class:lnkDocumentToFunctionalCI' => '关联 文档/功能项',
'Class:lnkDocumentToFunctionalCI+' => '',
'Class:lnkDocumentToFunctionalCI/Attribute:functionalci_id' => '功能项',
'Class:lnkDocumentToFunctionalCI/Attribute:functionalci_id+' => '',
@@ -1574,7 +1574,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Menu:ConfigManagement:Misc' => '杂项',
'Menu:Group' => '配置组',
'Menu:Group+' => '配置组',
'Menu:OSVersion' => 'OS 版本',
'Menu:OSVersion' => 'OS版本',
'Menu:OSVersion+' => '',
'Menu:Software' => '软件清单',
'Menu:Software+' => '软件清单',

View File

@@ -25,7 +25,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'itop-core-update:UI:SelectUpdateFile' => '应用升级',
'itop-core-update:UI:ConfirmUpdate' => ' 升级',
'itop-core-update:UI:UpdateCoreFiles' => '应用升级',
'iTopUpdate:UI:MaintenanceModeActive' => 'The application is currently under maintenance, no user can access the application. You have to run a setup or restore the application archive to return in normal mode.~~',
'iTopUpdate:UI:MaintenanceModeActive' => '此应用当前维护中,不允许任何用户访问.必须运行安装或恢复归档来使其处于正常模式.',
'itop-core-update:UI:UpdateDone' => '应用升级',
'itop-core-update/Operation:SelectUpdateFile/Title' => '应用升级',
@@ -94,15 +94,15 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'iTopUpdate:Error:MissingFunction' => '无法开始升级, 功能缺失',
'iTopUpdate:Error:MissingFile' => '缺少文件: %1$s',
'iTopUpdate:Error:CorruptedFile' => '文件 %1$s 已损坏',
'iTopUpdate:Error:BadFileFormat' => '上传的不是zip 文件',
'iTopUpdate:Error:BadFileFormat' => '上传的不是zip格式的文件',
'iTopUpdate:Error:BadFileContent' => '升级文件不是程序升级包',
'iTopUpdate:Error:BadItopProduct' => '升级文件与您的系统不兼容',
'iTopUpdate:Error:Copy' => '错误, 无法复制 \'%1$s\' 到 \'%2$s\'',
'iTopUpdate:Error:FileNotFound' => '文件找不到',
'iTopUpdate:Error:NoFile' => '没有提供文件',
'iTopUpdate:Error:InvalidToken' => '无效的 token',
'iTopUpdate:Error:InvalidToken' => '无效的token',
'iTopUpdate:Error:UpdateFailed' => '升级失败',
'iTopUpdate:Error:FileUploadMaxSizeTooSmall' => '上传上限太小. 请调整 PHP 配置.',
'iTopUpdate:Error:FileUploadMaxSizeTooSmall' => '上传上限太小. 请调整PHP配置.',
'iTopUpdate:UI:RestoreArchive' => '您可以从归档文件 \'%1$s\' 还原应用程序',
'iTopUpdate:UI:RestoreBackup' => '您可以从 \'%1$s\' 还原数据库',

View File

@@ -62,7 +62,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:FAQ/Attribute:error_code+' => '',
'Class:FAQ/Attribute:key_words' => '关键字',
'Class:FAQ/Attribute:key_words+' => '',
'Class:FAQ/Attribute:domains' => '领域~~',
'Class:FAQ/Attribute:domains' => '范围',
));
//
@@ -70,19 +70,19 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:FAQCategory' => 'FAQ 类别',
'Class:FAQCategory+' => 'FAQ 类别',
'Class:FAQCategory' => 'FAQ类别',
'Class:FAQCategory+' => 'FAQ类别',
'Class:FAQCategory/Attribute:name' => '名称',
'Class:FAQCategory/Attribute:name+' => '',
'Class:FAQCategory/Attribute:faq_list' => 'FAQ',
'Class:FAQCategory/Attribute:faq_list+' => '类别FAQ 相关的所有常见问题',
'Class:FAQCategory/Attribute:faq_list+' => '类别FAQ 相关的所有常见问题',
));
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Menu:ProblemManagement' => '问题管理',
'Menu:ProblemManagement+' => '问题管理',
'Menu:Problem:Shortcuts' => '快捷方式',
'Menu:FAQCategory' => 'FAQ 类别',
'Menu:FAQCategory+' => '所有FAQ 类别',
'Menu:FAQCategory+' => '所有FAQ类别',
'Menu:FAQ' => 'FAQ',
'Menu:FAQ+' => '所有FAQ',
'Brick:Portal:FAQ:Menu' => 'FAQ',

View File

@@ -24,7 +24,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
// Errors
'FilesInformation:Error:MissingFile' => '文件丢失: %1$s~~',
'FilesInformation:Error:CorruptedFile' => '文件 %1$s 已损坏',
'FilesInformation:Error:ListCorruptedFile' => 'File(s) corrupted: %1$s~~',
'FilesInformation:Error:ListCorruptedFile' => '已损坏的文件: %1$s',
'FilesInformation:Error:CantWriteToFile' => '文件 %1$s 无法写入',
));

View File

@@ -15,12 +15,13 @@
<module_parameters>
<parameters id="itop-hub-connector" _delta="define">
<url>https://www.itophub.io</url>
<route_landing>/my-instances/landing-from-remote</route_landing>
<route_landing_stateless>/stateless-remote-itop/landing-from-remote-stateless</route_landing_stateless>
<route_fetch_unread_messages>/api/messages</route_fetch_unread_messages>
<route_mark_all_messages_as_read>/api/messages/mark-all-as-read</route_mark_all_messages_as_read>
<route_view_all_messages>/messages</route_view_all_messages>
<route_landing>/my-instances/landing-from-remote</route_landing>
<route_landing_stateless>/stateless-remote-itop/landing-from-remote-stateless</route_landing_stateless>
<route_fetch_unread_messages>/api/messages</route_fetch_unread_messages>
<route_mark_all_messages_as_read>/api/messages/mark-all-as-read</route_mark_all_messages_as_read>
<route_view_all_messages>/messages</route_view_all_messages>
<setup_url>../pages/exec.php?exec_module=itop-hub-connector&amp;exec_page=launch.php&amp;target=inform_after_setup</setup_url>
<rgpd_url>https://www.itophub.io/page/data-privacy</rgpd_url>
</parameters>
</module_parameters>
</itop_design>

View File

@@ -23,46 +23,46 @@
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
// Dictionary entries go here
'Menu:iTopHub' => 'iTop Hub',
'Menu:iTopHub:Register' => '进入 iTop Hub ',
'Menu:iTopHub:Register+' => '进入 iTop Hub 更新您的组件',
'Menu:iTopHub:Register:Description' => '<p>进入 iTop Hub 社区平台!</br>寻找您想要的内容和信息, 管理本机扩展或安装新的扩展.</br><br/>通过这个页面连接到iTop Hub, 本机的信息也会被推送到 iTop Hub 上.</p>',
'Menu:iTopHub:Register' => '进入iTop Hub',
'Menu:iTopHub:Register+' => '进入iTop Hub更新您的组件',
'Menu:iTopHub:Register:Description' => '<p>进入iTop Hub社区平台!</br>寻找您想要的内容和信息, 管理本机扩展或安装新的扩展.</br><br/>通过这个页面连接到iTop Hub, 本机的信息也会被推送到 iTop Hub 上.</p>',
'Menu:iTopHub:MyExtensions' => '已安装的扩展',
'Menu:iTopHub:MyExtensions+' => '查看本机已安装的扩展',
'Menu:iTopHub:BrowseExtensions' => '从 iTop Hub 获取扩展',
'Menu:iTopHub:BrowseExtensions+' => '去 iTop Hub 浏览更多的扩展',
'Menu:iTopHub:BrowseExtensions:Description' => '<p>进入 iTop Hub 商店, 一站式查找各种iTop 扩展的地方 !</br>寻找符合您要求的扩展.</br><br/>通过这个页面连接到iTop Hub, 本机的信息也会被推送到 iTop Hub 上.</p>',
'Menu:iTopHub:BrowseExtensions' => '从iTop Hub获取扩展',
'Menu:iTopHub:BrowseExtensions+' => '去iTop Hub浏览更多的扩展',
'Menu:iTopHub:BrowseExtensions:Description' => '<p>进入iTop Hub商店, 一站式查找各种iTop扩展的地方 !</br>寻找符合您要求的扩展.</br><br/>通过这个页面连接到iTop Hub, 本机的信息也会被推送到 iTop Hub 上.</p>',
'iTopHub:GoBtn' => '进入iTop Hub',
'iTopHub:CloseBtn' => '关闭',
'iTopHub:GoBtn:Tooltip' => '跳到 www.itophub.io',
'iTopHub:OpenInNewWindow' => '从新窗口打开 iTop Hub',
'iTopHub:AutoSubmit' => '不再询问. 下次自动进入 iTop Hub .',
'iTopHub:OpenInNewWindow' => '从新窗口打开iTop Hub',
'iTopHub:AutoSubmit' => '不再询问. 下次自动进入iTop Hub .',
'UI:About:RemoteExtensionSource' => 'iTop Hub',
'iTopHub:Explanation' => '点击这个按钮您将被引导至 iTop Hub.',
'iTopHub:Explanation' => '点击这个按钮您将被引导至iTop Hub.',
'iTopHub:BackupFreeDiskSpaceIn' => '%1$s free disk space in %2$s.',
'iTopHub:FailedToCheckFreeDiskSpace' => '检查空闲的磁盘空间失败.',
'iTopHub:BackupFreeDiskSpaceIn' => '%1$s 可用磁盘空间位于 %2$s.',
'iTopHub:FailedToCheckFreeDiskSpace' => '检查可用磁盘空间失败.',
'iTopHub:BackupOk' => '备份成功.',
'iTopHub:BackupFailed' => '备份失败!',
'iTopHub:Landing:Status' => '安装状态',
'iTopHub:Landing:Install' => '扩展安装进行中...',
'iTopHub:CompiledOK' => '编译成功.',
'iTopHub:ConfigurationSafelyReverted' => '安装时发生错误!<br/>iTop 配置将不会改变.',
'iTopHub:ConfigurationSafelyReverted' => '安装时发生错误!<br/>iTop配置将不会改变.',
'iTopHub:FailAuthent' => '认证失败.',
'iTopHub:InstalledExtensions' => '本机已安装的扩展',
'iTopHub:ExtensionCategory:Manual' => '手动安装的扩展',
'iTopHub:ExtensionCategory:Manual+' => '下列已安装的扩展是手动将文件放置到 %1$s 目录的:',
'iTopHub:ExtensionCategory:Remote' => '从 iTop Hub 安装的扩展',
'iTopHub:ExtensionCategory:Remote+' => '下列已安装的扩展是来自 iTop Hub:',
'iTopHub:ExtensionCategory:Remote' => '从iTop Hub 安装的扩展',
'iTopHub:ExtensionCategory:Remote+' => '下列已安装的扩展是来自iTop Hub:',
'iTopHub:NoExtensionInThisCategory' => '尚未安装扩展',
'iTopHub:NoExtensionInThisCategory+' => '浏览 iTop Hub ,去寻找符合您喜欢的扩展吧.',
'iTopHub:NoExtensionInThisCategory+' => '浏览iTop Hub,去寻找符合您喜欢的扩展吧.',
'iTopHub:ExtensionNotInstalled' => '未安装',
'iTopHub:GetMoreExtensions' => '从 iTop Hub 获取扩展...',
'iTopHub:GetMoreExtensions' => '从iTop Hub获取扩展...',
'iTopHub:LandingWelcome' => '恭喜! 下列来自 iTop Hub 的扩展已被下载并安装到本机.',
'iTopHub:LandingWelcome' => '恭喜! 下列来自iTop Hub的扩展已被下载并安装到本机.',
'iTopHub:GoBackToITopBtn' => '返回'.ITOP_APPLICATION_SHORT,
'iTopHub:Uncompressing' => '扩展解压中...',
'iTopHub:InstallationWelcome' => '安装来自 iTop Hub 的扩展',
'iTopHub:InstallationWelcome' => '安装来自iTop Hub的扩展',
'iTopHub:DBBackupLabel' => '本机备份',
'iTopHub:DBBackupSentence' => '在升级之前,备份数据库和 '.ITOP_APPLICATION_SHORT.' 配置文件',
'iTopHub:DeployBtn' => '安装 !',
@@ -75,7 +75,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'iTopHub:InstallationProgress:DatabaseBackup' => ITOP_APPLICATION_SHORT.' 本机备份...',
'iTopHub:InstallationProgress:ExtensionsInstallation' => '安装扩展',
'iTopHub:InstallationEffect:MissingDependencies' => '扩展无法安装,因为未知的依赖.',
'iTopHub:InstallationEffect:MissingDependencies_Details' => '扩展依赖模块: %1$s',
'iTopHub:InstallationEffect:MissingDependencies_Details' => '扩展依赖模块: %1$s',
'iTopHub:InstallationProgress:InstallationSuccessful' => '安装成功!',
'iTopHub:InstallationStatus:Installed_Version' => '%1$s 版本: %2$s.',

View File

@@ -116,8 +116,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Incident/Attribute:origin/Value:monitoring+' => '监控',
'Class:Incident/Attribute:origin/Value:phone' => '电话',
'Class:Incident/Attribute:origin/Value:phone+' => '电话',
'Class:Incident/Attribute:origin/Value:portal' => 'portal',
'Class:Incident/Attribute:origin/Value:portal+' => 'portal',
'Class:Incident/Attribute:origin/Value:portal' => '门户',
'Class:Incident/Attribute:origin/Value:portal+' => '门户',
'Class:Incident/Attribute:service_id' => '服务',
'Class:Incident/Attribute:service_id+' => '',
'Class:Incident/Attribute:service_name' => '服务名称',
@@ -164,8 +164,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Incident/Attribute:resolution_code+' => '',
'Class:Incident/Attribute:resolution_code/Value:assistance' => '外部支持',
'Class:Incident/Attribute:resolution_code/Value:assistance+' => '外部支持',
'Class:Incident/Attribute:resolution_code/Value:bug fixed' => 'bug 修复',
'Class:Incident/Attribute:resolution_code/Value:bug fixed+' => 'bug 修复',
'Class:Incident/Attribute:resolution_code/Value:bug fixed' => '缺陷修复',
'Class:Incident/Attribute:resolution_code/Value:bug fixed+' => '缺陷修复',
'Class:Incident/Attribute:resolution_code/Value:hardware repair' => '硬件维修',
'Class:Incident/Attribute:resolution_code/Value:hardware repair+' => '硬件维修',
'Class:Incident/Attribute:resolution_code/Value:other' => '其它',
@@ -188,14 +188,14 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Incident/Attribute:parent_change_id+' => '',
'Class:Incident/Attribute:parent_change_ref' => '变更编号',
'Class:Incident/Attribute:parent_change_ref+' => '',
'Class:Incident/Attribute:parent_problem_id' => 'Parent problem id~~',
'Class:Incident/Attribute:parent_problem_id' => '父级问题',
'Class:Incident/Attribute:parent_problem_id+' => '~~',
'Class:Incident/Attribute:parent_problem_ref' => 'Parent problem ref~~',
'Class:Incident/Attribute:parent_problem_ref' => '父级问题编号',
'Class:Incident/Attribute:parent_problem_ref+' => '~~',
'Class:Incident/Attribute:related_request_list' => '相关需求',
'Class:Incident/Attribute:related_request_list+' => '事件相关的所有需求',
'Class:Incident/Attribute:related_request_list+' => '事件相关的所有需求',
'Class:Incident/Attribute:child_incidents_list' => '衍生事件',
'Class:Incident/Attribute:child_incidents_list+' => '事件相关的所有子事件',
'Class:Incident/Attribute:child_incidents_list+' => '事件相关的所有子事件',
'Class:Incident/Attribute:public_log' => '评论',
'Class:Incident/Attribute:public_log+' => '',
'Class:Incident/Attribute:user_satisfaction' => '用户满意度',
@@ -210,7 +210,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:Incident/Attribute:user_satisfaction/Value:4+' => '非常不满意',
'Class:Incident/Attribute:user_comment' => '用户评论',
'Class:Incident/Attribute:user_comment+' => '',
'Class:Incident/Attribute:parent_incident_id_friendlyname' => '好记的父级事件ID名称',
'Class:Incident/Attribute:parent_incident_id_friendlyname' => '父级事件名称',
'Class:Incident/Attribute:parent_incident_id_friendlyname+' => '',
'Class:Incident/Stimulus:ev_assign' => '分配',
'Class:Incident/Stimulus:ev_assign+' => '',

View File

@@ -85,9 +85,9 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:KnownError/Attribute:version' => '版本',
'Class:KnownError/Attribute:version+' => '',
'Class:KnownError/Attribute:ci_list' => '配置项',
'Class:KnownError/Attribute:ci_list+' => '已知错误相关的所有配置项',
'Class:KnownError/Attribute:ci_list+' => '已知错误相关的所有配置项',
'Class:KnownError/Attribute:document_list' => '文档',
'Class:KnownError/Attribute:document_list+' => '已知错误相关的所有文档',
'Class:KnownError/Attribute:document_list+' => '已知错误相关的所有文档',
));
//

View File

@@ -0,0 +1,2 @@
# Extension OAuth 2.0 client

View File

@@ -0,0 +1,24 @@
<?php
/**
* @copyright Copyright (C) 2010-2022 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\OAuthClient;
use Combodo\iTop\OAuthClient\Controller\AjaxOauthClientController;
require_once(APPROOT.'application/startup.inc.php');
if (version_compare(ITOP_DESIGN_LATEST_VERSION , '3.0') >= 0) {
$sTemplates = MODULESROOT.'itop-oauth-client/templates';
} else {
$sTemplates = MODULESROOT.'itop-oauth-client/templates/legacy';
}
$oUpdateController = new AjaxOauthClientController($sTemplates, 'itop-oauth-client');
$oUpdateController->AllowOnlyAdmin();
$oUpdateController->SetDefaultOperation('CreateMailbox');
$oUpdateController->HandleOperation();

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 977 B

After

Width:  |  Height:  |  Size: 977 B

View File

@@ -0,0 +1,99 @@
/**
* @copyright Copyright (C) 2010-2022 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
// Function used to open OAuth popup
var oWindowObjectReference = null;
var sPreviousUrl = null;
var oListener = null;
var sOAuthAjaxURI = null;
var sOAuthObjClass = null;
var sOAuthObjKey = null;
var sOAuthReturnURI = null;
const oOnOauthSuccess = function (event) {
if (oListener !== null) {
clearInterval(oListener);
}
$.post(
sOAuthAjaxURI,
{
operation: 'GetDisplayAuthenticationResults',
class: sOAuthObjClass,
id: sOAuthObjKey,
redirect_url: event.data
},
function (oData) {
window.location = oData.data;
}
);
}
const oOpenSignInWindow = function (url, name) {
// Remove any existing event listener
window.removeEventListener('message', oOnOauthSuccess);
if (oListener !== null) {
clearInterval(oListener);
}
// Window features
const sWindowFeatures = 'toolbar=no, menubar=no, width=600, height=700, top=100, left=100';
if (oWindowObjectReference === null || oWindowObjectReference.closed) {
/* If the pointer to the window object in memory does not exist
or if such pointer exists but the window was closed */
oWindowObjectReference = window.open(url, name, sWindowFeatures);
} else if (sPreviousUrl !== url) {
/* If the resource to load is different,
then we load it in the already opened secondary window, and then
we bring such window back on top/in front of its parent window. */
oWindowObjectReference = window.open(url, name, sWindowFeatures);
oWindowObjectReference.focus();
} else {
/* Else the window reference must exist and the window
is not closed; therefore, we can bring it back on top of any other
window with the focus() method. There would be no need to re-create
the window or to reload the referenced resource. */
oWindowObjectReference.focus();
}
/* Let know every second our child window that we're waiting for it to complete,
once we reach our landing page, it'll send us a reply
*/
oListener = window.setInterval(function () {
if (oWindowObjectReference.closed) {
clearInterval(oListener);
}
oWindowObjectReference.postMessage('anyone', sOAuthReturnURI);
}, 1000);
/* Once we receive a response, transmit it to the server to get authenticate and display
results
*/
window.addEventListener('message', oOnOauthSuccess, false);
// Assign the previous URL
sPreviousUrl = url;
};
const OAuthConnect = function(sClass, sId, sAjaxUri, sReturnUri) {
sOAuthAjaxURI = sAjaxUri;
sOAuthObjClass = sClass;
sOAuthObjKey = sId;
sOAuthReturnURI = sReturnUri;
$.post(
sOAuthAjaxURI,
{
operation: 'GetOAuthAuthorizationUrl',
class: sOAuthObjClass,
id: sOAuthObjKey
},
function (oData) {
if (oData.status === 'success') {
oOpenSignInWindow(oData.data.authorization_url, 'OAuth authorization')
}
}
);
}

View File

@@ -0,0 +1,16 @@
{
"config": {
"classmap-authoritative": true
},
"autoload": {
"psr-4": {
"Combodo\\iTop\\OAuthClient\\": "src"
}
},
"name": "combodo/itop-oauth-client",
"type": "itop-extension",
"description": "Remote authentication for OAuth 2.0",
"require": {
"composer-runtime-api": "^2.0"
}
}

View File

@@ -0,0 +1,20 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "285a4d33f818950c151bb893193d2cce",
"packages": [],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"composer-runtime-api": "^2.0"
},
"platform-dev": [],
"plugin-api-version": "2.1.0"
}

View File

@@ -0,0 +1,74 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('CS CZ', 'Czech', 'Čeština', [
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:OAuthClient' => 'OAuth Client~~',
'Menu:OAuthClient+' => '~~',
'Menu:GenerateTokens' => 'Generate access tokens...~~',
'Menu:RegenerateTokens' => 'Regenerate access tokens...~~',
'itop-oauth-client/Operation:CreateMailBox/Title' => 'Mailbox creation~~',
'itop-oauth-client:UsedForSMTP' => 'This OAuth client is used for SMTP~~',
'itop-oauth-client:TestSMTP' => 'Email send test~~',
'itop-oauth-client:MissingOAuthClient' => 'Missing Oauth client for user name %1$s~~',
'itop-oauth-client:Message:MissingToken' => 'Generate access token before using this OAuth client~~',
'itop-oauth-client:Message:TokenCreated' => 'Access token created~~',
'itop-oauth-client:Message:TokenRecreated' => 'Access token regenerated~~',
]);
//
// Class: OAuthClient
//
Dict::Add('CS CZ', 'Czech', 'Čeština', [
'Class:OAuthClient' => 'Oauth Client~~',
'Class:OAuthClient/Attribute:provider' => 'Provider~~',
'Class:OAuthClient/Attribute:provider+' => '~~',
'Class:OAuthClient/Attribute:name' => 'Login~~',
'Class:OAuthClient/Attribute:name+' => '~~',
'Class:OAuthClient/Attribute:scope' => 'Scope~~',
'Class:OAuthClient/Attribute:scope+' => '~~',
'Class:OAuthClient/Attribute:description' => 'Description~~',
'Class:OAuthClient/Attribute:description+' => '~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => '~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
'Class:OAuthClient/Attribute:client_secret+' => '~~',
'Class:OAuthClient/Attribute:refresh_token' => 'Refresh token~~',
'Class:OAuthClient/Attribute:refresh_token+' => '~~',
'Class:OAuthClient/Attribute:refresh_token_expiration' => 'Refresh token expiration~~',
'Class:OAuthClient/Attribute:refresh_token_expiration+' => '~~',
'Class:OAuthClient/Attribute:token' => 'Access token~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClient/Attribute:redirect_url' => 'Redirect url~~',
'Class:OAuthClient/Attribute:redirect_url+' => '~~',
'Class:OAuthClient/Attribute:mailbox_list' => 'Mailbox list~~',
'Class:OAuthClient/Attribute:mailbox_list+' => '~~',
]);
//
// Class: OAuthClientAzure
//
Dict::Add('CS CZ', 'Czech', 'Čeština', [
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
]);
//
// Class: OAuthClientGoogle
//
Dict::Add('CS CZ', 'Czech', 'Čeština', [
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
]);

View File

@@ -0,0 +1,74 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('DA DA', 'Danish', 'Dansk', [
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:OAuthClient' => 'OAuth Client~~',
'Menu:OAuthClient+' => '~~',
'Menu:GenerateTokens' => 'Generate access tokens...~~',
'Menu:RegenerateTokens' => 'Regenerate access tokens...~~',
'itop-oauth-client/Operation:CreateMailBox/Title' => 'Mailbox creation~~',
'itop-oauth-client:UsedForSMTP' => 'This OAuth client is used for SMTP~~',
'itop-oauth-client:TestSMTP' => 'Email send test~~',
'itop-oauth-client:MissingOAuthClient' => 'Missing Oauth client for user name %1$s~~',
'itop-oauth-client:Message:MissingToken' => 'Generate access token before using this OAuth client~~',
'itop-oauth-client:Message:TokenCreated' => 'Access token created~~',
'itop-oauth-client:Message:TokenRecreated' => 'Access token regenerated~~',
]);
//
// Class: OAuthClient
//
Dict::Add('DA DA', 'Danish', 'Dansk', [
'Class:OAuthClient' => 'Oauth Client~~',
'Class:OAuthClient/Attribute:provider' => 'Provider~~',
'Class:OAuthClient/Attribute:provider+' => '~~',
'Class:OAuthClient/Attribute:name' => 'Login~~',
'Class:OAuthClient/Attribute:name+' => '~~',
'Class:OAuthClient/Attribute:scope' => 'Scope~~',
'Class:OAuthClient/Attribute:scope+' => '~~',
'Class:OAuthClient/Attribute:description' => 'Description~~',
'Class:OAuthClient/Attribute:description+' => '~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => '~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
'Class:OAuthClient/Attribute:client_secret+' => '~~',
'Class:OAuthClient/Attribute:refresh_token' => 'Refresh token~~',
'Class:OAuthClient/Attribute:refresh_token+' => '~~',
'Class:OAuthClient/Attribute:refresh_token_expiration' => 'Refresh token expiration~~',
'Class:OAuthClient/Attribute:refresh_token_expiration+' => '~~',
'Class:OAuthClient/Attribute:token' => 'Access token~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClient/Attribute:redirect_url' => 'Redirect url~~',
'Class:OAuthClient/Attribute:redirect_url+' => '~~',
'Class:OAuthClient/Attribute:mailbox_list' => 'Mailbox list~~',
'Class:OAuthClient/Attribute:mailbox_list+' => '~~',
]);
//
// Class: OAuthClientAzure
//
Dict::Add('DA DA', 'Danish', 'Dansk', [
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
]);
//
// Class: OAuthClientGoogle
//
Dict::Add('DA DA', 'Danish', 'Dansk', [
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
]);

View File

@@ -0,0 +1,301 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.1">
<constants/>
<classes>
<class id="OAuthClient" _delta="define">
<parent>cmdbAbstractObject</parent>
<properties>
<category>cloud,searchable</category>
<abstract>true</abstract>
<key_type>autoincrement</key_type>
<db_table>priv_oauth_client</db_table>
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<attributes>
<attribute id="provider"/>
<attribute id="name"/>
</attributes>
</naming>
<display_template/>
<icon/>
<reconciliation>
<attributes>
<attribute id="provider"/>
<attribute id="name"/>
</attributes>
</reconciliation>
</properties>
<fields>
<field id="provider" xsi:type="AttributeString">
<sql>provider</sql>
<default_value/>
<is_null_allowed>false</is_null_allowed>
</field>
<field id="name" xsi:type="AttributeString">
<sql>name</sql>
<default_value/>
<is_null_allowed>false</is_null_allowed>
</field>
<field id="status" xsi:type="AttributeEnum">
<always_load_in_tables>true</always_load_in_tables>
<values>
<value id="active">
<code>active</code>
<style>
<main_color>$ibo-lifecycle-active-state-primary-color</main_color>
<complementary_color>$ibo-lifecycle-active-state-secondary-color</complementary_color>
<decoration_classes/>
</style>
</value>
<value id="inactive">
<code>inactive</code>
<style>
<main_color>$ibo-lifecycle-inactive-state-primary-color</main_color>
<complementary_color>$ibo-lifecycle-inactive-state-secondary-color</complementary_color>
<decoration_classes/>
</style>
</value>
</values>
<sql>status</sql>
<default_value>inactive</default_value>
<is_null_allowed>false</is_null_allowed>
</field>
<field id="description" xsi:type="AttributeText">
<sql>description</sql>
<default_value/>
<is_null_allowed>true</is_null_allowed>
</field>
<field id="client_id" xsi:type="AttributeText">
<sql>client_id</sql>
<default_value/>
<is_null_allowed>false</is_null_allowed>
</field>
<field id="client_secret" xsi:type="AttributeText">
<sql>client_secret</sql>
<default_value/>
<is_null_allowed>false</is_null_allowed>
</field>
<field id="refresh_token" xsi:type="AttributeText">
<sql>refresh_token</sql>
<default_value/>
<is_null_allowed>true</is_null_allowed>
<tracking_level>none</tracking_level>
</field>
<field id="refresh_token_expiration" xsi:type="AttributeDateTime">
<sql>refresh_token_expiration</sql>
<default_value/>
<is_null_allowed>true</is_null_allowed>
<tracking_level>none</tracking_level>
</field>
<field id="token" xsi:type="AttributeText">
<sql>token</sql>
<default_value/>
<is_null_allowed>true</is_null_allowed>
<tracking_level>none</tracking_level>
</field>
<field id="token_expiration" xsi:type="AttributeDateTime">
<sql>token_expiration</sql>
<default_value/>
<is_null_allowed>true</is_null_allowed>
<tracking_level>none</tracking_level>
</field>
<field id="redirect_url" xsi:type="AttributeURL">
<sql>redirect_url</sql>
<default_value/>
<target>_blank</target>
<is_null_allowed>true</is_null_allowed>
</field>
<field id="mailbox_list" xsi:type="AttributeLinkedSet">
<linked_class>MailInboxOAuth</linked_class>
<ext_key_to_me>oauth_client_id</ext_key_to_me>
<count_min>0</count_min>
<count_max>0</count_max>
</field>
</fields>
<methods>
<method id="DisplayBareHeader">
<static>false</static>
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[
public function DisplayBareHeader(WebPage $oPage, $bEditMode = false)
{
parent::DisplayBareHeader($oPage, $bEditMode);
if (!$bEditMode) {
$oConfig = utils::GetConfig();
$sScope = $this->Get('scope');
if ($this->Get('status') == 'inactive') {
$oPage->p('<b>'.Dict::S('itop-oauth-client:Message:MissingToken').'</b>');
} elseif (($sScope == 'SMTP' || $sScope == 'EMail') && $oConfig->Get('email_transport_smtp.username') == $this->Get('name')) {
$sLabel = Dict::S('itop-oauth-client:UsedForSMTP');
$sTestLabel = Dict::S('itop-oauth-client:TestSMTP');
$sTestURL = utils::GetAbsoluteUrlAppRoot().'setup/email.test.php';
$oPage->p("<b>$sLabel</b>&nbsp;<a href='$sTestURL' target='_blank'>$sTestLabel</a>");
}
}
}
]]></code>
</method>
<method id="GetAttributeFlags">
<static>false</static>
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
{
if ($sAttCode == 'status') {
return OPT_ATT_READONLY;
}
return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
}
]]></code>
</method>
<method id="GetInitialStateAttributeFlags">
<static>false</static>
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[
public function GetInitialStateAttributeFlags($sAttCode, &$aReasons = array())
{
if ($sAttCode == 'status') {
return OPT_ATT_READONLY;
}
return parent::GetInitialStateAttributeFlags($sAttCode, $aReasons);
}
]]></code>
</method>
<method id="GetDefaultMailServer">
<static>false</static>
<access>public</access>
<code><![CDATA[
public function GetDefaultMailServer()
{
return 'imap.'.$this->Get('provider').'.com';
}
]]></code>
</method>
<method id="GetDefaultMailServerPort">
<static>false</static>
<access>public</access>
<code><![CDATA[
public function GetDefaultMailServerPort()
{
return 993;
}
]]></code>
</method>
<method id="GetAccessToken">
<static>false</static>
<access>public</access>
<code><![CDATA[
public function GetAccessToken()
{
if ($this->Get('status') == 'active') {
return new \League\OAuth2\Client\Token\AccessToken([
'access_token' => $this->Get('token'),
'expires_in' => date_format(new DateTime($this->Get('token_expiration')), 'U') - time(),
'refresh_token' => $this->Get('refresh_token'),
'token_type' => 'Bearer',
]);
}
return null;
}
]]></code>
</method>
<method id="SetAccessToken">
<static>false</static>
<access>public</access>
<code><![CDATA[
public function SetAccessToken(\League\OAuth2\Client\Token\AccessTokenInterface $oAccessToken)
{
$this->Set('token', $oAccessToken->getToken());
$this->Set('token_expiration', date(AttributeDateTime::GetSQLFormat(), $oAccessToken->getExpires()));
if (!empty($oAccessToken->getRefreshToken())) {
$this->Set('refresh_token', $oAccessToken->getRefreshToken());
}
$this->Set('status', 'active');
$this->DBUpdate();
}
]]></code>
</method>
</methods>
<presentation>
<details>
<items>
<item id="name">
<rank>1</rank>
</item>
<item id="description">
<rank>2</rank>
</item>
<item id="provider">
<rank>3</rank>
</item>
<item id="redirect_url">
<rank>5</rank>
</item>
<item id="client_id">
<rank>6</rank>
</item>
<item id="client_secret">
<rank>7</rank>
</item>
<item id="mailbox_list">
<rank>8</rank>
</item>
</items>
</details>
<list>
<items>
<item id="status">
<rank>1</rank>
</item>
<item id="provider">
<rank>3</rank>
</item>
</items>
</list>
<search>
<items>
<item id="name">
<rank>1</rank>
</item>
<item id="provider">
<rank>2</rank>
</item>
</items>
</search>
<default_search>
<items>
<item id="name">
<rank>1</rank>
</item>
<item id="provider">
<rank>2</rank>
</item>
</items>
</default_search>
</presentation>
</class>
</classes>
<menus>
<menu id="OAuthClient" xsi:type="OQLMenuNode" _delta="define">
<rank>100</rank>
<parent>ConfigurationTools</parent>
<oql><![CDATA[SELECT OAuthClient]]></oql>
<do_search>1</do_search>
<enable_admin_only>0</enable_admin_only>
<enable_class>OAuthClient</enable_class>
<enable_action>UR_ACTION_READ</enable_action>
</menu>
</menus>
<user_rights>
<groups>
</groups>
<profiles>
</profiles>
</user_rights>
</itop_design>

View File

@@ -0,0 +1,74 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('DE DE', 'German', 'Deutsch', [
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:OAuthClient' => 'OAuth Client~~',
'Menu:OAuthClient+' => '~~',
'Menu:GenerateTokens' => 'Generate access token...~~',
'Menu:RegenerateTokens' => 'Regenerate access token...~~',
'itop-oauth-client/Operation:CreateMailBox/Title' => 'Mailbox creation~~',
'itop-oauth-client:UsedForSMTP' => 'This OAuth client is used for SMTP~~',
'itop-oauth-client:TestSMTP' => 'Email send test~~',
'itop-oauth-client:MissingOAuthClient' => 'Missing Oauth client for user name %1$s~~',
'itop-oauth-client:Message:MissingToken' => 'Generate access token before using this OAuth client~~',
'itop-oauth-client:Message:TokenCreated' => 'Access token created~~',
'itop-oauth-client:Message:TokenRecreated' => 'Access token regenerated~~',
]);
//
// Class: OAuthClient
//
Dict::Add('DE DE', 'German', 'Deutsch', [
'Class:OAuthClient' => 'Oauth Client~~',
'Class:OAuthClient/Attribute:provider' => 'Provider~~',
'Class:OAuthClient/Attribute:provider+' => '~~',
'Class:OAuthClient/Attribute:name' => 'Login~~',
'Class:OAuthClient/Attribute:name+' => '~~',
'Class:OAuthClient/Attribute:scope' => 'Scope~~',
'Class:OAuthClient/Attribute:scope+' => '~~',
'Class:OAuthClient/Attribute:description' => 'Description~~',
'Class:OAuthClient/Attribute:description+' => '~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => '~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
'Class:OAuthClient/Attribute:client_secret+' => '~~',
'Class:OAuthClient/Attribute:refresh_token' => 'Refresh token~~',
'Class:OAuthClient/Attribute:refresh_token+' => '~~',
'Class:OAuthClient/Attribute:refresh_token_expiration' => 'Refresh token expiration~~',
'Class:OAuthClient/Attribute:refresh_token_expiration+' => '~~',
'Class:OAuthClient/Attribute:token' => 'Access token~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClient/Attribute:redirect_url' => 'Redirect url~~',
'Class:OAuthClient/Attribute:redirect_url+' => '~~',
'Class:OAuthClient/Attribute:mailbox_list' => 'Mailbox list~~',
'Class:OAuthClient/Attribute:mailbox_list+' => '~~',
]);
//
// Class: OAuthClientAzure
//
Dict::Add('DE DE', 'German', 'Deutsch', [
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
]);
//
// Class: OAuthClientGoogle
//
Dict::Add('DE DE', 'German', 'Deutsch', [
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
]);

View File

@@ -0,0 +1,78 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('EN US', 'English', 'English', [
'Menu:CreateMailbox' => 'Create a mailbox...',
'Menu:OAuthClient' => 'OAuth Client',
'Menu:OAuthClient+' => '',
'Menu:GenerateTokens' => 'Generate access token...',
'Menu:RegenerateTokens' => 'Regenerate access token...',
'itop-oauth-client/Operation:CreateMailBox/Title' => 'Mailbox creation',
'itop-oauth-client:UsedForSMTP' => 'This OAuth client is used for SMTP',
'itop-oauth-client:TestSMTP' => 'Email send test',
'itop-oauth-client:MissingOAuthClient' => 'Missing Oauth client for user name %1$s',
'itop-oauth-client:Message:MissingToken' => 'Generate access token before using this OAuth client',
'itop-oauth-client:Message:TokenCreated' => 'Access token created',
'itop-oauth-client:Message:TokenRecreated' => 'Access token regenerated',
]);
//
// Class: OAuthClient
//
Dict::Add('EN US', 'English', 'English', [
'Class:OAuthClient' => 'Oauth Client',
'Class:OAuthClient/Attribute:provider' => 'Provider',
'Class:OAuthClient/Attribute:provider+' => '',
'Class:OAuthClient/Attribute:name' => 'Login',
'Class:OAuthClient/Attribute:name+' => '',
'Class:OAuthClient/Attribute:scope' => 'Scope',
'Class:OAuthClient/Attribute:scope+' => '',
'Class:OAuthClient/Attribute:status' => 'Status',
'Class:OAuthClient/Attribute:status+' => '',
'Class:OAuthClient/Attribute:status/Value:active' => 'Access token generated',
'Class:OAuthClient/Attribute:status/Value:inactive' => 'No Access token',
'Class:OAuthClient/Attribute:description' => 'Description',
'Class:OAuthClient/Attribute:description+' => '',
'Class:OAuthClient/Attribute:client_id' => 'Client id',
'Class:OAuthClient/Attribute:client_id+' => '',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret',
'Class:OAuthClient/Attribute:client_secret+' => '',
'Class:OAuthClient/Attribute:refresh_token' => 'Refresh token',
'Class:OAuthClient/Attribute:refresh_token+' => '',
'Class:OAuthClient/Attribute:refresh_token_expiration' => 'Refresh token expiration',
'Class:OAuthClient/Attribute:refresh_token_expiration+' => '',
'Class:OAuthClient/Attribute:token' => 'Access token',
'Class:OAuthClient/Attribute:token+' => '',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration',
'Class:OAuthClient/Attribute:token_expiration+' => '',
'Class:OAuthClient/Attribute:redirect_url' => 'Redirect url',
'Class:OAuthClient/Attribute:redirect_url+' => '',
'Class:OAuthClient/Attribute:mailbox_list' => 'Mailbox list',
'Class:OAuthClient/Attribute:mailbox_list+' => '',
]);
//
// Class: OAuthClientAzure
//
Dict::Add('EN US', 'English', 'English', [
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)',
]);
//
// Class: OAuthClientGoogle
//
Dict::Add('EN US', 'English', 'English', [
'Class:OAuthClientGoogle' => 'OAuth client for Google',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)',
]);

View File

@@ -0,0 +1,74 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', [
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:OAuthClient' => 'OAuth Client~~',
'Menu:OAuthClient+' => '~~',
'Menu:GenerateTokens' => 'Generate access tokens...~~',
'Menu:RegenerateTokens' => 'Regenerate access tokens...~~',
'itop-oauth-client/Operation:CreateMailBox/Title' => 'Mailbox creation~~',
'itop-oauth-client:UsedForSMTP' => 'This OAuth client is used for SMTP~~',
'itop-oauth-client:TestSMTP' => 'Email send test~~',
'itop-oauth-client:MissingOAuthClient' => 'Missing Oauth client for user name %1$s~~',
'itop-oauth-client:Message:MissingToken' => 'Generate access token before using this OAuth client~~',
'itop-oauth-client:Message:TokenCreated' => 'Access token created~~',
'itop-oauth-client:Message:TokenRecreated' => 'Access token regenerated~~',
]);
//
// Class: OAuthClient
//
Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', [
'Class:OAuthClient' => 'Oauth Client~~',
'Class:OAuthClient/Attribute:provider' => 'Provider~~',
'Class:OAuthClient/Attribute:provider+' => '~~',
'Class:OAuthClient/Attribute:name' => 'Login~~',
'Class:OAuthClient/Attribute:name+' => '~~',
'Class:OAuthClient/Attribute:scope' => 'Scope~~',
'Class:OAuthClient/Attribute:scope+' => '~~',
'Class:OAuthClient/Attribute:description' => 'Description~~',
'Class:OAuthClient/Attribute:description+' => '~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => '~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
'Class:OAuthClient/Attribute:client_secret+' => '~~',
'Class:OAuthClient/Attribute:refresh_token' => 'Refresh token~~',
'Class:OAuthClient/Attribute:refresh_token+' => '~~',
'Class:OAuthClient/Attribute:refresh_token_expiration' => 'Refresh token expiration~~',
'Class:OAuthClient/Attribute:refresh_token_expiration+' => '~~',
'Class:OAuthClient/Attribute:token' => 'Access token~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClient/Attribute:redirect_url' => 'Redirect url~~',
'Class:OAuthClient/Attribute:redirect_url+' => '~~',
'Class:OAuthClient/Attribute:mailbox_list' => 'Mailbox list~~',
'Class:OAuthClient/Attribute:mailbox_list+' => '~~',
]);
//
// Class: OAuthClientAzure
//
Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', [
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
]);
//
// Class: OAuthClientGoogle
//
Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', [
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
]);

View File

@@ -0,0 +1,78 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('FR FR', 'French', 'Français', [
'Menu:CreateMailbox' => 'Créer une boite mail...',
'Menu:OAuthClient' => 'Client OAuth',
'Menu:OAuthClient+' => '',
'Menu:GenerateTokens' => 'Créer un jeton d\'accès...',
'Menu:RegenerateTokens' => 'Recréer un jeton d\'accès..',
'itop-oauth-client/Operation:CreateMailBox/Title' => 'Création de boite mail',
'itop-oauth-client:UsedForSMTP' => 'Ce client Oauth est utilisé pour SMTP',
'itop-oauth-client:TestSMTP' => 'Tester l\'envoi de mail',
'itop-oauth-client:MissingOAuthClient' => 'Il n\'y a pas de client OAuth pour l\'utilisateur %1$s',
'itop-oauth-client:Message:MissingToken' => 'Générez le jeton d\'accès avant d\'utiliser ce client OAuth',
'itop-oauth-client:Message:TokenCreated' => 'Le jeton d\'accès à été créé',
'itop-oauth-client:Message:TokenRecreated' => 'Le jeton d\'accès à été renouvelé',
]);
//
// Class: OAuthClient
//
Dict::Add('FR FR', 'French', 'Français', [
'Class:OAuthClient' => 'Client OAuth',
'Class:OAuthClient/Attribute:provider' => 'Fournisseur',
'Class:OAuthClient/Attribute:provider+' => '',
'Class:OAuthClient/Attribute:name' => 'Login',
'Class:OAuthClient/Attribute:name+' => '',
'Class:OAuthClient/Attribute:scope' => 'Niveaux d\'accès',
'Class:OAuthClient/Attribute:scope+' => '',
'Class:OAuthClient/Attribute:description' => 'Description',
'Class:OAuthClient/Attribute:description+' => '',
'Class:OAuthClient/Attribute:client_id' => 'ID Client',
'Class:OAuthClient/Attribute:client_id+' => '',
'Class:OAuthClient/Attribute:client_secret' => 'Code secret du client',
'Class:OAuthClient/Attribute:client_secret+' => '',
'Class:OAuthClient/Attribute:refresh_token' => 'Jeton de renouvellement',
'Class:OAuthClient/Attribute:refresh_token+' => '',
'Class:OAuthClient/Attribute:refresh_token_expiration' => 'Date d\'expiration du jeton de renouvellement',
'Class:OAuthClient/Attribute:refresh_token_expiration+' => '',
'Class:OAuthClient/Attribute:token' => 'Jeton d\'accès',
'Class:OAuthClient/Attribute:token+' => '',
'Class:OAuthClient/Attribute:token_expiration' => 'Date d\'expiration du jeton d\'accès',
'Class:OAuthClient/Attribute:token_expiration+' => '',
'Class:OAuthClient/Attribute:redirect_url' => 'URL de redirection',
'Class:OAuthClient/Attribute:redirect_url+' => '',
'Class:OAuthClient/Attribute:mailbox_list' => 'Mailbox list',
'Class:OAuthClient/Attribute:mailbox_list+' => '',
]);
//
// Class: OAuthClientAzure
//
Dict::Add('FR FR', 'French', 'Français', [
'Class:OAuthClientAzure' => 'Client OAuth pour Microsoft Azure',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)',
]);
//
// Class: OAuthClientGoogle
//
Dict::Add('FR FR', 'French', 'Français', [
'Class:OAuthClientGoogle' => 'Client OAuth pour Google',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)',
]);
// Additional language entries not present in English dict
Dict::Add('FR FR', 'French', 'Français', array(
'Class:OAuthClient/Name' => '%1$s-%%2$~',
));

View File

@@ -0,0 +1,74 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('HU HU', 'Hungarian', 'Magyar', [
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:OAuthClient' => 'OAuth Client~~',
'Menu:OAuthClient+' => '~~',
'Menu:GenerateTokens' => 'Generate access tokens...~~',
'Menu:RegenerateTokens' => 'Regenerate access tokens...~~',
'itop-oauth-client/Operation:CreateMailBox/Title' => 'Mailbox creation~~',
'itop-oauth-client:UsedForSMTP' => 'This OAuth client is used for SMTP~~',
'itop-oauth-client:TestSMTP' => 'Email send test~~',
'itop-oauth-client:MissingOAuthClient' => 'Missing Oauth client for user name %1$s~~',
'itop-oauth-client:Message:MissingToken' => 'Generate access token before using this OAuth client~~',
'itop-oauth-client:Message:TokenCreated' => 'Access token created~~',
'itop-oauth-client:Message:TokenRecreated' => 'Access token regenerated~~',
]);
//
// Class: OAuthClient
//
Dict::Add('HU HU', 'Hungarian', 'Magyar', [
'Class:OAuthClient' => 'Oauth Client~~',
'Class:OAuthClient/Attribute:provider' => 'Provider~~',
'Class:OAuthClient/Attribute:provider+' => '~~',
'Class:OAuthClient/Attribute:name' => 'Login~~',
'Class:OAuthClient/Attribute:name+' => '~~',
'Class:OAuthClient/Attribute:scope' => 'Scope~~',
'Class:OAuthClient/Attribute:scope+' => '~~',
'Class:OAuthClient/Attribute:description' => 'Description~~',
'Class:OAuthClient/Attribute:description+' => '~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => '~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
'Class:OAuthClient/Attribute:client_secret+' => '~~',
'Class:OAuthClient/Attribute:refresh_token' => 'Refresh token~~',
'Class:OAuthClient/Attribute:refresh_token+' => '~~',
'Class:OAuthClient/Attribute:refresh_token_expiration' => 'Refresh token expiration~~',
'Class:OAuthClient/Attribute:refresh_token_expiration+' => '~~',
'Class:OAuthClient/Attribute:token' => 'Access token~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClient/Attribute:redirect_url' => 'Redirect url~~',
'Class:OAuthClient/Attribute:redirect_url+' => '~~',
'Class:OAuthClient/Attribute:mailbox_list' => 'Mailbox list~~',
'Class:OAuthClient/Attribute:mailbox_list+' => '~~',
]);
//
// Class: OAuthClientAzure
//
Dict::Add('HU HU', 'Hungarian', 'Magyar', [
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
]);
//
// Class: OAuthClientGoogle
//
Dict::Add('HU HU', 'Hungarian', 'Magyar', [
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
]);

View File

@@ -0,0 +1,24 @@
<?php
/**
* @copyright Copyright (C) 2010-2022 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\OAuthClient;
use Combodo\iTop\OAuthClient\Controller\OAuthClientController;
require_once(APPROOT.'application/startup.inc.php');
if (version_compare(ITOP_DESIGN_LATEST_VERSION , '3.0') >= 0) {
$sTemplates = MODULESROOT.'itop-oauth-client/templates';
} else {
$sTemplates = MODULESROOT.'itop-oauth-client/templates/legacy';
}
$oUpdateController = new OAuthClientController($sTemplates, 'itop-oauth-client');
$oUpdateController->AllowOnlyAdmin();
$oUpdateController->SetDefaultOperation('CreateMailbox');
$oUpdateController->HandleOperation();

View File

@@ -0,0 +1,74 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('IT IT', 'Italian', 'Italiano', [
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:OAuthClient' => 'OAuth Client~~',
'Menu:OAuthClient+' => '~~',
'Menu:GenerateTokens' => 'Generate access tokens...~~',
'Menu:RegenerateTokens' => 'Regenerate access tokens...~~',
'itop-oauth-client/Operation:CreateMailBox/Title' => 'Mailbox creation~~',
'itop-oauth-client:UsedForSMTP' => 'This OAuth client is used for SMTP~~',
'itop-oauth-client:TestSMTP' => 'Email send test~~',
'itop-oauth-client:MissingOAuthClient' => 'Missing Oauth client for user name %1$s~~',
'itop-oauth-client:Message:MissingToken' => 'Generate access token before using this OAuth client~~',
'itop-oauth-client:Message:TokenCreated' => 'Access token created~~',
'itop-oauth-client:Message:TokenRecreated' => 'Access token regenerated~~',
]);
//
// Class: OAuthClient
//
Dict::Add('IT IT', 'Italian', 'Italiano', [
'Class:OAuthClient' => 'Oauth Client~~',
'Class:OAuthClient/Attribute:provider' => 'Provider~~',
'Class:OAuthClient/Attribute:provider+' => '~~',
'Class:OAuthClient/Attribute:name' => 'Login~~',
'Class:OAuthClient/Attribute:name+' => '~~',
'Class:OAuthClient/Attribute:scope' => 'Scope~~',
'Class:OAuthClient/Attribute:scope+' => '~~',
'Class:OAuthClient/Attribute:description' => 'Description~~',
'Class:OAuthClient/Attribute:description+' => '~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => '~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
'Class:OAuthClient/Attribute:client_secret+' => '~~',
'Class:OAuthClient/Attribute:refresh_token' => 'Refresh token~~',
'Class:OAuthClient/Attribute:refresh_token+' => '~~',
'Class:OAuthClient/Attribute:refresh_token_expiration' => 'Refresh token expiration~~',
'Class:OAuthClient/Attribute:refresh_token_expiration+' => '~~',
'Class:OAuthClient/Attribute:token' => 'Access token~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClient/Attribute:redirect_url' => 'Redirect url~~',
'Class:OAuthClient/Attribute:redirect_url+' => '~~',
'Class:OAuthClient/Attribute:mailbox_list' => 'Mailbox list~~',
'Class:OAuthClient/Attribute:mailbox_list+' => '~~',
]);
//
// Class: OAuthClientAzure
//
Dict::Add('IT IT', 'Italian', 'Italiano', [
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
]);
//
// Class: OAuthClientGoogle
//
Dict::Add('IT IT', 'Italian', 'Italiano', [
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
]);

View File

@@ -0,0 +1,74 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('JA JP', 'Japanese', '日本語', [
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:OAuthClient' => 'OAuth Client~~',
'Menu:OAuthClient+' => '~~',
'Menu:GenerateTokens' => 'Generate access tokens...~~',
'Menu:RegenerateTokens' => 'Regenerate access tokens...~~',
'itop-oauth-client/Operation:CreateMailBox/Title' => 'Mailbox creation~~',
'itop-oauth-client:UsedForSMTP' => 'This OAuth client is used for SMTP~~',
'itop-oauth-client:TestSMTP' => 'Email send test~~',
'itop-oauth-client:MissingOAuthClient' => 'Missing Oauth client for user name %1$s~~',
'itop-oauth-client:Message:MissingToken' => 'Generate access token before using this OAuth client~~',
'itop-oauth-client:Message:TokenCreated' => 'Access token created~~',
'itop-oauth-client:Message:TokenRecreated' => 'Access token regenerated~~',
]);
//
// Class: OAuthClient
//
Dict::Add('JA JP', 'Japanese', '日本語', [
'Class:OAuthClient' => 'Oauth Client~~',
'Class:OAuthClient/Attribute:provider' => 'Provider~~',
'Class:OAuthClient/Attribute:provider+' => '~~',
'Class:OAuthClient/Attribute:name' => 'Login~~',
'Class:OAuthClient/Attribute:name+' => '~~',
'Class:OAuthClient/Attribute:scope' => 'Scope~~',
'Class:OAuthClient/Attribute:scope+' => '~~',
'Class:OAuthClient/Attribute:description' => 'Description~~',
'Class:OAuthClient/Attribute:description+' => '~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => '~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
'Class:OAuthClient/Attribute:client_secret+' => '~~',
'Class:OAuthClient/Attribute:refresh_token' => 'Refresh token~~',
'Class:OAuthClient/Attribute:refresh_token+' => '~~',
'Class:OAuthClient/Attribute:refresh_token_expiration' => 'Refresh token expiration~~',
'Class:OAuthClient/Attribute:refresh_token_expiration+' => '~~',
'Class:OAuthClient/Attribute:token' => 'Access token~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClient/Attribute:redirect_url' => 'Redirect url~~',
'Class:OAuthClient/Attribute:redirect_url+' => '~~',
'Class:OAuthClient/Attribute:mailbox_list' => 'Mailbox list~~',
'Class:OAuthClient/Attribute:mailbox_list+' => '~~',
]);
//
// Class: OAuthClientAzure
//
Dict::Add('JA JP', 'Japanese', '日本語', [
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
]);
//
// Class: OAuthClientGoogle
//
Dict::Add('JA JP', 'Japanese', '日本語', [
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
]);

View File

@@ -0,0 +1,54 @@
<?php
//
// iTop module definition file
//
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-oauth-client/3.1.0',
array(
// Identification
//
'label' => 'OAuth 2.0 client',
'category' => 'business',
// Setup
//
'dependencies' => array(
'itop-welcome-itil/3.1.0,',
),
'mandatory' => false,
'visible' => true,
// Components
//
'datamodel' => array(
'vendor/autoload.php',
'model.itop-oauth-client.php', // Contains the PHP code generated by the "compilation" of datamodel.remote-authent-oauth.xml
'src/Model/OAuthClientGoogle.php',
'src/Model/OAuthClientAzure.php',
'src/Service/PopupMenuExtension.php',
),
'webservice' => array(
),
'data.struct' => array(
// add your 'structure' definition XML files here,
),
'data.sample' => array(
// add your sample data XML files here,
),
// Documentation
//
'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any
'doc.more_information' => '', // hyperlink to more information, if any
// Default settings
//
'settings' => array(
// Module specific settings go here, if any
),
)
);

View File

@@ -0,0 +1,74 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('NL NL', 'Dutch', 'Nederlands', [
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:OAuthClient' => 'OAuth Client~~',
'Menu:OAuthClient+' => '~~',
'Menu:GenerateTokens' => 'Generate access tokens...~~',
'Menu:RegenerateTokens' => 'Regenerate access tokens...~~',
'itop-oauth-client/Operation:CreateMailBox/Title' => 'Mailbox creation~~',
'itop-oauth-client:UsedForSMTP' => 'This OAuth client is used for SMTP~~',
'itop-oauth-client:TestSMTP' => 'Email send test~~',
'itop-oauth-client:MissingOAuthClient' => 'Missing Oauth client for user name %1$s~~',
'itop-oauth-client:Message:MissingToken' => 'Generate access token before using this OAuth client~~',
'itop-oauth-client:Message:TokenCreated' => 'Access token created~~',
'itop-oauth-client:Message:TokenRecreated' => 'Access token regenerated~~',
]);
//
// Class: OAuthClient
//
Dict::Add('NL NL', 'Dutch', 'Nederlands', [
'Class:OAuthClient' => 'Oauth Client~~',
'Class:OAuthClient/Attribute:provider' => 'Provider~~',
'Class:OAuthClient/Attribute:provider+' => '~~',
'Class:OAuthClient/Attribute:name' => 'Login~~',
'Class:OAuthClient/Attribute:name+' => '~~',
'Class:OAuthClient/Attribute:scope' => 'Scope~~',
'Class:OAuthClient/Attribute:scope+' => '~~',
'Class:OAuthClient/Attribute:description' => 'Description~~',
'Class:OAuthClient/Attribute:description+' => '~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => '~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
'Class:OAuthClient/Attribute:client_secret+' => '~~',
'Class:OAuthClient/Attribute:refresh_token' => 'Refresh token~~',
'Class:OAuthClient/Attribute:refresh_token+' => '~~',
'Class:OAuthClient/Attribute:refresh_token_expiration' => 'Refresh token expiration~~',
'Class:OAuthClient/Attribute:refresh_token_expiration+' => '~~',
'Class:OAuthClient/Attribute:token' => 'Access token~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClient/Attribute:redirect_url' => 'Redirect url~~',
'Class:OAuthClient/Attribute:redirect_url+' => '~~',
'Class:OAuthClient/Attribute:mailbox_list' => 'Mailbox list~~',
'Class:OAuthClient/Attribute:mailbox_list+' => '~~',
]);
//
// Class: OAuthClientAzure
//
Dict::Add('NL NL', 'Dutch', 'Nederlands', [
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
]);
//
// Class: OAuthClientGoogle
//
Dict::Add('NL NL', 'Dutch', 'Nederlands', [
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
]);

View File

@@ -0,0 +1,74 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:OAuthClient' => 'OAuth Client~~',
'Menu:OAuthClient+' => '~~',
'Menu:GenerateTokens' => 'Generate access tokens...~~',
'Menu:RegenerateTokens' => 'Regenerate access tokens...~~',
'itop-oauth-client/Operation:CreateMailBox/Title' => 'Mailbox creation~~',
'itop-oauth-client:UsedForSMTP' => 'This OAuth client is used for SMTP~~',
'itop-oauth-client:TestSMTP' => 'Email send test~~',
'itop-oauth-client:MissingOAuthClient' => 'Missing Oauth client for user name %1$s~~',
'itop-oauth-client:Message:MissingToken' => 'Generate access token before using this OAuth client~~',
'itop-oauth-client:Message:TokenCreated' => 'Access token created~~',
'itop-oauth-client:Message:TokenRecreated' => 'Access token regenerated~~',
]);
//
// Class: OAuthClient
//
Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
'Class:OAuthClient' => 'Oauth Client~~',
'Class:OAuthClient/Attribute:provider' => 'Provider~~',
'Class:OAuthClient/Attribute:provider+' => '~~',
'Class:OAuthClient/Attribute:name' => 'Login~~',
'Class:OAuthClient/Attribute:name+' => '~~',
'Class:OAuthClient/Attribute:scope' => 'Scope~~',
'Class:OAuthClient/Attribute:scope+' => '~~',
'Class:OAuthClient/Attribute:description' => 'Description~~',
'Class:OAuthClient/Attribute:description+' => '~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => '~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
'Class:OAuthClient/Attribute:client_secret+' => '~~',
'Class:OAuthClient/Attribute:refresh_token' => 'Refresh token~~',
'Class:OAuthClient/Attribute:refresh_token+' => '~~',
'Class:OAuthClient/Attribute:refresh_token_expiration' => 'Refresh token expiration~~',
'Class:OAuthClient/Attribute:refresh_token_expiration+' => '~~',
'Class:OAuthClient/Attribute:token' => 'Access token~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClient/Attribute:redirect_url' => 'Redirect url~~',
'Class:OAuthClient/Attribute:redirect_url+' => '~~',
'Class:OAuthClient/Attribute:mailbox_list' => 'Mailbox list~~',
'Class:OAuthClient/Attribute:mailbox_list+' => '~~',
]);
//
// Class: OAuthClientAzure
//
Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
]);
//
// Class: OAuthClientGoogle
//
Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
]);

View File

@@ -0,0 +1,74 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('RU RU', 'Russian', 'Русский', [
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:OAuthClient' => 'OAuth Client~~',
'Menu:OAuthClient+' => '~~',
'Menu:GenerateTokens' => 'Generate access tokens...~~',
'Menu:RegenerateTokens' => 'Regenerate access tokens...~~',
'itop-oauth-client/Operation:CreateMailBox/Title' => 'Mailbox creation~~',
'itop-oauth-client:UsedForSMTP' => 'This OAuth client is used for SMTP~~',
'itop-oauth-client:TestSMTP' => 'Email send test~~',
'itop-oauth-client:MissingOAuthClient' => 'Missing Oauth client for user name %1$s~~',
'itop-oauth-client:Message:MissingToken' => 'Generate access token before using this OAuth client~~',
'itop-oauth-client:Message:TokenCreated' => 'Access token created~~',
'itop-oauth-client:Message:TokenRecreated' => 'Access token regenerated~~',
]);
//
// Class: OAuthClient
//
Dict::Add('RU RU', 'Russian', 'Русский', [
'Class:OAuthClient' => 'Oauth Client~~',
'Class:OAuthClient/Attribute:provider' => 'Provider~~',
'Class:OAuthClient/Attribute:provider+' => '~~',
'Class:OAuthClient/Attribute:name' => 'Login~~',
'Class:OAuthClient/Attribute:name+' => '~~',
'Class:OAuthClient/Attribute:scope' => 'Scope~~',
'Class:OAuthClient/Attribute:scope+' => '~~',
'Class:OAuthClient/Attribute:description' => 'Description~~',
'Class:OAuthClient/Attribute:description+' => '~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => '~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
'Class:OAuthClient/Attribute:client_secret+' => '~~',
'Class:OAuthClient/Attribute:refresh_token' => 'Refresh token~~',
'Class:OAuthClient/Attribute:refresh_token+' => '~~',
'Class:OAuthClient/Attribute:refresh_token_expiration' => 'Refresh token expiration~~',
'Class:OAuthClient/Attribute:refresh_token_expiration+' => '~~',
'Class:OAuthClient/Attribute:token' => 'Access token~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClient/Attribute:redirect_url' => 'Redirect url~~',
'Class:OAuthClient/Attribute:redirect_url+' => '~~',
'Class:OAuthClient/Attribute:mailbox_list' => 'Mailbox list~~',
'Class:OAuthClient/Attribute:mailbox_list+' => '~~',
]);
//
// Class: OAuthClientAzure
//
Dict::Add('RU RU', 'Russian', 'Русский', [
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
]);
//
// Class: OAuthClientGoogle
//
Dict::Add('RU RU', 'Russian', 'Русский', [
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
]);

View File

@@ -0,0 +1,74 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:OAuthClient' => 'OAuth Client~~',
'Menu:OAuthClient+' => '~~',
'Menu:GenerateTokens' => 'Generate access tokens...~~',
'Menu:RegenerateTokens' => 'Regenerate access tokens...~~',
'itop-oauth-client/Operation:CreateMailBox/Title' => 'Mailbox creation~~',
'itop-oauth-client:UsedForSMTP' => 'This OAuth client is used for SMTP~~',
'itop-oauth-client:TestSMTP' => 'Email send test~~',
'itop-oauth-client:MissingOAuthClient' => 'Missing Oauth client for user name %1$s~~',
'itop-oauth-client:Message:MissingToken' => 'Generate access token before using this OAuth client~~',
'itop-oauth-client:Message:TokenCreated' => 'Access token created~~',
'itop-oauth-client:Message:TokenRecreated' => 'Access token regenerated~~',
]);
//
// Class: OAuthClient
//
Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
'Class:OAuthClient' => 'Oauth Client~~',
'Class:OAuthClient/Attribute:provider' => 'Provider~~',
'Class:OAuthClient/Attribute:provider+' => '~~',
'Class:OAuthClient/Attribute:name' => 'Login~~',
'Class:OAuthClient/Attribute:name+' => '~~',
'Class:OAuthClient/Attribute:scope' => 'Scope~~',
'Class:OAuthClient/Attribute:scope+' => '~~',
'Class:OAuthClient/Attribute:description' => 'Description~~',
'Class:OAuthClient/Attribute:description+' => '~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => '~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
'Class:OAuthClient/Attribute:client_secret+' => '~~',
'Class:OAuthClient/Attribute:refresh_token' => 'Refresh token~~',
'Class:OAuthClient/Attribute:refresh_token+' => '~~',
'Class:OAuthClient/Attribute:refresh_token_expiration' => 'Refresh token expiration~~',
'Class:OAuthClient/Attribute:refresh_token_expiration+' => '~~',
'Class:OAuthClient/Attribute:token' => 'Access token~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClient/Attribute:redirect_url' => 'Redirect url~~',
'Class:OAuthClient/Attribute:redirect_url+' => '~~',
'Class:OAuthClient/Attribute:mailbox_list' => 'Mailbox list~~',
'Class:OAuthClient/Attribute:mailbox_list+' => '~~',
]);
//
// Class: OAuthClientAzure
//
Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
]);
//
// Class: OAuthClientGoogle
//
Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
]);

View File

@@ -0,0 +1,77 @@
<?php
/**
* @copyright Copyright (C) 2010-2022 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\OAuthClient\Controller;
use cmdbAbstractObject;
use Combodo\iTop\Application\TwigBase\Controller\Controller;
use Combodo\iTop\Core\Authentication\Client\OAuth\OAuthClientProviderFactory;
use Dict;
use IssueLog;
use MetaModel;
use utils;
class AjaxOauthClientController extends Controller
{
const LOG_CHANNEL = 'OAuth';
public function OperationGetOAuthAuthorizationUrl()
{
$sClass = utils::ReadParam('class');
$sId = utils::ReadParam('id');
IssueLog::Debug("GetAuthorizationUrl for $sClass::$sId", self::LOG_CHANNEL);
/** @var \OAuthClient $oOAuthClient */
$oOAuthClient = MetaModel::GetObject($sClass, $sId);
$aResult = ['status' => 'success', 'data' => []];
$sAuthorizationUrl = OAuthClientProviderFactory::GetAuthorizationUrl($oOAuthClient);
$aResult['data']['authorization_url'] = $sAuthorizationUrl;
$this->DisplayJSONPage($aResult);
}
public function OperationGetDisplayAuthenticationResults()
{
$sClass = utils::ReadParam('class');
$sId = utils::ReadParam('id');
IssueLog::Debug("GetDisplayAuthenticationResults for $sClass::$sId", self::LOG_CHANNEL);
/** @var \OAuthClient $oOAuthClient */
$oOAuthClient = MetaModel::GetObject($sClass, $sId);
$bIsCreation = empty($oOAuthClient->Get('token'));
$sRedirectUrl = utils::ReadParam('redirect_url', '', false, 'raw');
$sRedirectUrlQuery = parse_url($sRedirectUrl)['query'];
$aQuery = [];
parse_str($sRedirectUrlQuery, $aQuery);
$sCode = $aQuery['code'];
$oAccessToken = OAuthClientProviderFactory::GetAccessTokenFromCode($oOAuthClient, $sCode);
$oOAuthClient->SetAccessToken($oAccessToken);
cmdbAbstractObject::SetSessionMessage(
$sClass,
$sId,
"$sClass:$sId:TokenCreated",
$bIsCreation ? Dict::S('itop-oauth-client:Message:TokenCreated') : Dict::S('itop-oauth-client:Message:TokenRecreated'),
'ok',
1,
true
);
$aResult = ['status' => 'success'];
$aResult['data'] = utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=details&class=$sClass&id=$sId";
$this->DisplayJSONPage($aResult);
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* @copyright Copyright (C) 2010-2022 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\OAuthClient\Controller;
use Combodo\iTop\Application\TwigBase\Controller\Controller;
use IssueLog;
use MetaModel;
use utils;
class OAuthClientController extends Controller
{
const LOG_CHANNEL = 'OAuth';
public function OperationCreateMailbox()
{
$aParams = [];
$sClass = utils::ReadParam('class');
$sId = utils::ReadParam('id');
IssueLog::Debug("CreateMailbox for $sClass::$sId", self::LOG_CHANNEL);
$oOAuthClient = MetaModel::GetObject($sClass, $sId);
$sLogin = $oOAuthClient->Get('name');
$sDefaultServer = $oOAuthClient->GetDefaultMailServer();
$sDefaultPort = $oOAuthClient->GetDefaultMailServerPort();
$aParams['sURL'] = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=new&class=MailInboxOAuth'.
'&default[mailbox]=INBOX'.
'&default[server]='.$sDefaultServer.
'&default[port]='.$sDefaultPort.
'&default[oauth_client_id]='.$sId.
'&default[login]='.$sLogin;
$this->DisplayPage($aParams);
}
}

View File

@@ -0,0 +1,128 @@
<?php
/**
* @copyright Copyright (C) 2010-2022 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Core\Authentication\Client\OAuth\OAuthClientProviderFactory;
class OAuthClientAzure extends OAuthClient
{
public static function Init()
{
$aParams = [
'category' => 'cloud',
'key_type' => 'autoincrement',
'name_attcode' => ['name', 'scope'],
'state_attcode' => '',
'reconc_keys' => ['provider', 'name'],
'db_table' => 'priv_oauth_client_azure',
'db_key_field' => 'id',
'icon' => utils::GetAbsoluteUrlModulesRoot().'itop-oauth-client/assets/img/icons8-azure.svg',
'db_finalclass_field' => '',
'uniqueness_rules' => [
'Username for scope' =>
[
'attributes' => ['name', 'scope'],
'filter' => null,
'disabled' => false,
'is_blocking' => true,
],
'OAuth Server' =>
[
'attributes' => ['provider', 'scope', 'client_id', 'client_secret'],
'filter' => null,
'disabled' => false,
'is_blocking' => true,
],
],
];
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeEnum('scope', [
'allowed_values' => new ValueSetEnum('EMail'),
'display_style' => 'list',
'sql' => 'scope',
'default_value' => 'EMail',
'is_null_allowed' => false,
'depends_on' => [],
'always_load_in_tables' => true,
]));
MetaModel::Init_SetZListItems('details', [
'name',
'status',
'description',
'provider',
'scope',
'redirect_url',
'client_id',
'client_secret',
'mailbox_list',
]);
MetaModel::Init_SetZListItems('standard_search', [
'name',
'provider',
'status',
]);
MetaModel::Init_SetZListItems('list', [
'status',
'provider',
]);
}
public function PrefillCreationForm(&$aContextParam)
{
$this->Set('provider', 'Azure');
$this->Set('redirect_url', OAuthClientProviderFactory::GetRedirectUri());
parent::PrefillCreationForm($aContextParam);
}
/**
* Compute read-only values
*
* @return void
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
*/
public function ComputeValues()
{
parent::ComputeValues();
if (empty($this->Get('provider'))) {
$this->Set('provider', 'Azure');
}
if (empty($this->Get('redirect_url'))) {
$this->Set('redirect_url', OAuthClientProviderFactory::GetRedirectUri());
}
}
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
{
if ($sAttCode == 'provider' || $sAttCode == 'redirect_url') {
return OPT_ATT_READONLY;
}
return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
}
public function GetInitialStateAttributeFlags($sAttCode, &$aReasons = array())
{
if ($sAttCode == 'provider' || $sAttCode == 'redirect_url') {
return OPT_ATT_READONLY;
}
return parent::GetInitialStateAttributeFlags($sAttCode, $aReasons);
}
public function GetDefaultMailServer()
{
return 'outlook.office365.com';
}
public function GetScope()
{
return 'https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send offline_access';
}
}

View File

@@ -0,0 +1,134 @@
<?php
/**
* @copyright Copyright (C) 2010-2022 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Core\Authentication\Client\OAuth\OAuthClientProviderFactory;
class OAuthClientGoogle extends OAuthClient
{
public static function Init()
{
$aParams = array
(
'category' => 'cloud',
'key_type' => 'autoincrement',
'name_attcode' => ['name', 'scope'],
'state_attcode' => '',
'reconc_keys' => ['provider', 'name'],
'db_table' => 'priv_oauth_client_google',
'db_key_field' => 'id',
'icon' => utils::GetAbsoluteUrlModulesRoot().'itop-oauth-client/assets/img/icons8-google.svg',
'db_finalclass_field' => '',
'uniqueness_rules' => [
'Username for scope' =>
[
'attributes' => ['name', 'scope'],
'filter' => null,
'disabled' => false,
'is_blocking' => true,
],
'OAuth Server' =>
[
'attributes' => ['provider', 'scope', 'client_id', 'client_secret'],
'filter' => null,
'disabled' => false,
'is_blocking' => true,
],
],
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeEnum('scope', [
'allowed_values' => new ValueSetEnum('EMail'),
'display_style' => 'list',
'sql' => 'scope',
'default_value' => 'EMail',
'is_null_allowed' => false,
'depends_on' => [],
'always_load_in_tables' => true,
]));
MetaModel::Init_SetZListItems('details', [
'name',
'status',
'description',
'provider',
'scope',
'redirect_url',
'client_id',
'client_secret',
'mailbox_list',
]);
MetaModel::Init_SetZListItems('standard_search', [
'name',
'provider',
'status',
]);
MetaModel::Init_SetZListItems('list', [
'status',
'provider',
]);
}
public function PrefillCreationForm(&$aContextParam)
{
$this->Set('provider', 'Google');
$this->Set('scope', 'EMail');
$this->Set('redirect_url', OAuthClientProviderFactory::GetRedirectUri());
parent::PrefillCreationForm($aContextParam);
}
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
{
if ($sAttCode == 'provider' || $sAttCode == 'scope' || $sAttCode == 'redirect_url') {
return OPT_ATT_READONLY;
}
return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
}
public function GetInitialStateAttributeFlags($sAttCode, &$aReasons = array())
{
if ($sAttCode == 'provider' || $sAttCode == 'scope' || $sAttCode == 'redirect_url') {
return OPT_ATT_READONLY;
}
return parent::GetInitialStateAttributeFlags($sAttCode, $aReasons);
}
/**
* Compute read-only values
*
* @return void
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
*/
public function ComputeValues()
{
parent::ComputeValues();
if (empty($this->Get('provider'))) {
$this->Set('provider', 'Google');
}
if (empty($this->Get('redirect_url'))) {
$this->Set('redirect_url', OAuthClientProviderFactory::GetRedirectUri());
}
if (empty($this->Get('scope'))) {
$this->Set('scope', 'EMail');
}
}
public function GetDefaultMailServer()
{
return 'imap.gmail.com';
}
public function GetScope()
{
return 'https://mail.google.com/';
}
}

View File

@@ -0,0 +1,79 @@
<?php
/**
* @copyright Copyright (C) 2010-2022 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\OAuthClient\Service;
use ApplicationContext;
use Combodo\iTop\Core\Authentication\Client\OAuth\OAuthClientProviderFactory;
use Dict;
use iPopupMenuExtension;
use JSPopupMenuItem;
use OAuthClient;
use SeparatorPopupMenuItem;
use URLPopupMenuItem;
use utils;
class PopupMenuExtension implements \iPopupMenuExtension
{
const MODULE_CODE = 'itop-oauth-client';
/**
* @inheritDoc
*/
public static function EnumItems($iMenuId, $param)
{
$aResult = [];
switch ($iMenuId) {
case iPopupMenuExtension::MENU_OBJDETAILS_ACTIONS:
$oObj = $param;
if ($oObj instanceof OAuthClient) {
$bHasToken = !empty($oObj->Get('token'));
$aResult[] = new SeparatorPopupMenuItem();
$oAppContext = new ApplicationContext();
$sMenu = $bHasToken ? 'Menu:RegenerateTokens' : 'Menu:GenerateTokens';
$sObjClass = get_class($oObj);
$sClass = $sObjClass;
$sId = $oObj->GetKey();
$sAjaxUri = utils::GetAbsoluteUrlModulePage(static::MODULE_CODE, 'ajax.php');
// Add a new menu item that triggers a custom JS function defined in our own javascript file: js/sample.js
$sJSFileUrl = utils::GetAbsoluteUrlModulesRoot().static::MODULE_CODE.'/assets/js/oauth_connect.js';
$sRedirectUri = OAuthClientProviderFactory::GetRedirectUri();
$aResult[] = new JSPopupMenuItem(
$sMenu.' from '.$sObjClass,
Dict::S($sMenu),
"OAuthConnect('$sClass', $sId, '$sAjaxUri', '$sRedirectUri')",
[$sJSFileUrl]
);
if ($bHasToken) {
$sScope = $oObj->Get('scope');
if ($sScope == 'EMail') {
$aParams = $oAppContext->GetAsHash();
$sMenu = 'Menu:CreateMailbox';
$sObjClass = get_class($oObj);
$aParams['class'] = $sObjClass;
$aParams['id'] = $oObj->GetKey();
$aParams['operation'] = 'CreateMailbox';
$aResult[] = new URLPopupMenuItem(
$sMenu.' from '.$sObjClass,
Dict::S($sMenu),
utils::GetAbsoluteUrlModulePage(static::MODULE_CODE, 'index.php', $aParams)
);
}
}
}
break;
default:
// Unknown type of menu, do nothing
break;
}
return $aResult;
}
}

View File

@@ -0,0 +1,3 @@
{# @copyright Copyright (C) 2010-2022 Combodo SARL #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}

View File

@@ -0,0 +1,4 @@
{# @copyright Copyright (C) 2010-2022 Combodo SARL #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}
window.location.href = '{{ sURL|raw }}'

View File

@@ -0,0 +1,74 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('TR TR', 'Turkish', 'Türkçe', [
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:OAuthClient' => 'OAuth Client~~',
'Menu:OAuthClient+' => '~~',
'Menu:GenerateTokens' => 'Generate access tokens...~~',
'Menu:RegenerateTokens' => 'Regenerate access tokens...~~',
'itop-oauth-client/Operation:CreateMailBox/Title' => 'Mailbox creation~~',
'itop-oauth-client:UsedForSMTP' => 'This OAuth client is used for SMTP~~',
'itop-oauth-client:TestSMTP' => 'Email send test~~',
'itop-oauth-client:MissingOAuthClient' => 'Missing Oauth client for user name %1$s~~',
'itop-oauth-client:Message:MissingToken' => 'Generate access token before using this OAuth client~~',
'itop-oauth-client:Message:TokenCreated' => 'Access token created~~',
'itop-oauth-client:Message:TokenRecreated' => 'Access token regenerated~~',
]);
//
// Class: OAuthClient
//
Dict::Add('TR TR', 'Turkish', 'Türkçe', [
'Class:OAuthClient' => 'Oauth Client~~',
'Class:OAuthClient/Attribute:provider' => 'Provider~~',
'Class:OAuthClient/Attribute:provider+' => '~~',
'Class:OAuthClient/Attribute:name' => 'Login~~',
'Class:OAuthClient/Attribute:name+' => '~~',
'Class:OAuthClient/Attribute:scope' => 'Scope~~',
'Class:OAuthClient/Attribute:scope+' => '~~',
'Class:OAuthClient/Attribute:description' => 'Description~~',
'Class:OAuthClient/Attribute:description+' => '~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => '~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
'Class:OAuthClient/Attribute:client_secret+' => '~~',
'Class:OAuthClient/Attribute:refresh_token' => 'Refresh token~~',
'Class:OAuthClient/Attribute:refresh_token+' => '~~',
'Class:OAuthClient/Attribute:refresh_token_expiration' => 'Refresh token expiration~~',
'Class:OAuthClient/Attribute:refresh_token_expiration+' => '~~',
'Class:OAuthClient/Attribute:token' => 'Access token~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClient/Attribute:redirect_url' => 'Redirect url~~',
'Class:OAuthClient/Attribute:redirect_url+' => '~~',
'Class:OAuthClient/Attribute:mailbox_list' => 'Mailbox list~~',
'Class:OAuthClient/Attribute:mailbox_list+' => '~~',
]);
//
// Class: OAuthClientAzure
//
Dict::Add('TR TR', 'Turkish', 'Türkçe', [
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
]);
//
// Class: OAuthClientGoogle
//
Dict::Add('TR TR', 'Turkish', 'Türkçe', [
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
]);

View File

@@ -0,0 +1,7 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitd52424b43ff18219f2ec935428aff074::getLoader();

View File

@@ -0,0 +1,572 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
/** @var ?string */
private $vendorDir;
// PSR-4
/**
* @var array[]
* @psalm-var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, array<int, string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* @var array[]
* @psalm-var array<string, array<string, string[]>>
*/
private $prefixesPsr0 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr0 = array();
/** @var bool */
private $useIncludePath = false;
/**
* @var string[]
* @psalm-var array<string, string>
*/
private $classMap = array();
/** @var bool */
private $classMapAuthoritative = false;
/**
* @var bool[]
* @psalm-var array<string, bool>
*/
private $missingClasses = array();
/** @var ?string */
private $apcuPrefix;
/**
* @var self[]
*/
private static $registeredLoaders = array();
/**
* @param ?string $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
}
/**
* @return string[]
*/
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
}
/**
* @return array[]
* @psalm-return array<string, array<int, string>>
*/
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
/**
* @return string[] Array of classname => path
* @psalm-var array<string, string>
*/
public function getClassMap()
{
return $this->classMap;
}
/**
* @param string[] $classMap Class to filename map
* @psalm-param array<string, string> $classMap
*
* @return void
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 base directories
*
* @return void
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*
* @return void
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*
* @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*
* @return void
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
}
/**
* Unregisters this instance as an autoloader.
*
* @return void
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
return null;
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
/**
* Returns the currently registered loaders indexed by their corresponding vendor directories.
*
* @return self[]
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
* @private
*/
function includeFile($file)
{
include $file;
}

View File

@@ -0,0 +1,350 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer;
use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;
/**
* This class is copied in every Composer installed project and available to all
*
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*/
class InstalledVersions
{
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
*/
private static $installed;
/**
* @var bool|null
*/
private static $canGetVendors;
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
private static $installedByVendor = array();
/**
* Returns a list of all package names which are present, either by being installed, replaced or provided
*
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackages()
{
$packages = array();
foreach (self::getInstalled() as $installed) {
$packages[] = array_keys($installed['versions']);
}
if (1 === \count($packages)) {
return $packages[0];
}
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
}
/**
* Returns a list of all package names with a specific type e.g. 'library'
*
* @param string $type
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackagesByType($type)
{
$packagesByType = array();
foreach (self::getInstalled() as $installed) {
foreach ($installed['versions'] as $name => $package) {
if (isset($package['type']) && $package['type'] === $type) {
$packagesByType[] = $name;
}
}
}
return $packagesByType;
}
/**
* Checks whether the given package is installed
*
* This also returns true if the package name is provided or replaced by another package
*
* @param string $packageName
* @param bool $includeDevRequirements
* @return bool
*/
public static function isInstalled($packageName, $includeDevRequirements = true)
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
}
}
return false;
}
/**
* Checks whether the given package satisfies a version constraint
*
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
*
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
*
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
* @param string $packageName
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
* @return bool
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints($constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
}
/**
* Returns a version constraint representing all the range(s) which are installed for a given package
*
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
* whether a given version of a package is installed, and not just whether it exists
*
* @param string $packageName
* @return string Version constraint usable with composer/semver
*/
public static function getVersionRanges($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
$ranges = array();
if (isset($installed['versions'][$packageName]['pretty_version'])) {
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
}
return implode(' || ', $ranges);
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['version'])) {
return null;
}
return $installed['versions'][$packageName]['version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getPrettyVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
return null;
}
return $installed['versions'][$packageName]['pretty_version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
*/
public static function getReference($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['reference'])) {
return null;
}
return $installed['versions'][$packageName]['reference'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
*/
public static function getInstallPath($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @return array
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
*/
public static function getRootPackage()
{
$installed = self::getInstalled();
return $installed[0]['root'];
}
/**
* Returns the raw installed.php data for custom implementations
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
*/
public static function getRawData()
{
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = include __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
return self::$installed;
}
/**
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
public static function getAllRawData()
{
return self::getInstalled();
}
/**
* Lets you reload the static array from another file
*
* This is only useful for complex integrations in which a project needs to use
* this class but then also needs to execute another project's autoloader in process,
* and wants to ensure both projects have access to their version of installed.php.
*
* A typical case would be PHPUnit, where it would need to make sure it reads all
* the data it needs from this class, then call reload() with
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
* the project in which it runs can then also use this class safely, without
* interference between PHPUnit's dependencies and the project's dependencies.
*
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
private static function getInstalled()
{
if (null === self::$canGetVendors) {
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
}
$installed = array();
if (self::$canGetVendors) {
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
}
}
}
}
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = require __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
$installed[] = self::$installed;
return $installed;
}
}

View File

@@ -0,0 +1,21 @@
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,13 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Combodo\\iTop\\OAuthClient\\Controller\\AjaxOauthClientController' => $baseDir . '/src/Controller/AjaxOauthClientController.php',
'Combodo\\iTop\\OAuthClient\\Controller\\OAuthClientController' => $baseDir . '/src/Controller/OAuthClientController.php',
'Combodo\\iTop\\OAuthClient\\Service\\PopupMenuExtension' => $baseDir . '/src/Service/PopupMenuExtension.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
);

View File

@@ -0,0 +1,9 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);

View File

@@ -0,0 +1,10 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Combodo\\iTop\\OAuthClient\\' => array($baseDir . '/src'),
);

View File

@@ -0,0 +1,46 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitd52424b43ff18219f2ec935428aff074
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitd52424b43ff18219f2ec935428aff074', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInitd52424b43ff18219f2ec935428aff074', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitd52424b43ff18219f2ec935428aff074::getInitializer($loader));
} else {
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->setClassMapAuthoritative(true);
$loader->register(true);
return $loader;
}
}

View File

@@ -0,0 +1,39 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInitd52424b43ff18219f2ec935428aff074
{
public static $prefixLengthsPsr4 = array (
'C' =>
array (
'Combodo\\iTop\\OAuthClient\\' => 25,
),
);
public static $prefixDirsPsr4 = array (
'Combodo\\iTop\\OAuthClient\\' =>
array (
0 => __DIR__ . '/../..' . '/src',
),
);
public static $classMap = array (
'Combodo\\iTop\\OAuthClient\\Controller\\AjaxOauthClientController' => __DIR__ . '/../..' . '/src/Controller/AjaxOauthClientController.php',
'Combodo\\iTop\\OAuthClient\\Controller\\OAuthClientController' => __DIR__ . '/../..' . '/src/Controller/OAuthClientController.php',
'Combodo\\iTop\\OAuthClient\\Service\\PopupMenuExtension' => __DIR__ . '/../..' . '/src/Service/PopupMenuExtension.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitd52424b43ff18219f2ec935428aff074::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitd52424b43ff18219f2ec935428aff074::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitd52424b43ff18219f2ec935428aff074::$classMap;
}, null, ClassLoader::class);
}
}

View File

@@ -0,0 +1,5 @@
{
"packages": [],
"dev": true,
"dev-package-names": []
}

View File

@@ -0,0 +1,23 @@
<?php return array(
'root' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'type' => 'itop-extension',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '1135896b3d084aa9df778bfbb724b7e992534989',
'name' => 'combodo/itop-oauth-client',
'dev' => true,
),
'versions' => array(
'combodo/itop-oauth-client' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'type' => 'itop-extension',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '1135896b3d084aa9df778bfbb724b7e992534989',
'dev_requirement' => false,
),
),
);

View File

@@ -0,0 +1,74 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:OAuthClient' => 'OAuth Client~~',
'Menu:OAuthClient+' => '~~',
'Menu:GenerateTokens' => 'Generate access tokens...~~',
'Menu:RegenerateTokens' => 'Regenerate access tokens...~~',
'itop-oauth-client/Operation:CreateMailBox/Title' => 'Mailbox creation~~',
'itop-oauth-client:UsedForSMTP' => 'This OAuth client is used for SMTP~~',
'itop-oauth-client:TestSMTP' => 'Email send test~~',
'itop-oauth-client:MissingOAuthClient' => 'Missing Oauth client for user name %1$s~~',
'itop-oauth-client:Message:MissingToken' => 'Generate access token before using this OAuth client~~',
'itop-oauth-client:Message:TokenCreated' => 'Access token created~~',
'itop-oauth-client:Message:TokenRecreated' => 'Access token regenerated~~',
]);
//
// Class: OAuthClient
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:OAuthClient' => 'Oauth Client~~',
'Class:OAuthClient/Attribute:provider' => 'Provider~~',
'Class:OAuthClient/Attribute:provider+' => '~~',
'Class:OAuthClient/Attribute:name' => 'Login~~',
'Class:OAuthClient/Attribute:name+' => '~~',
'Class:OAuthClient/Attribute:scope' => 'Scope~~',
'Class:OAuthClient/Attribute:scope+' => '~~',
'Class:OAuthClient/Attribute:description' => 'Description~~',
'Class:OAuthClient/Attribute:description+' => '~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => '~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
'Class:OAuthClient/Attribute:client_secret+' => '~~',
'Class:OAuthClient/Attribute:refresh_token' => 'Refresh token~~',
'Class:OAuthClient/Attribute:refresh_token+' => '~~',
'Class:OAuthClient/Attribute:refresh_token_expiration' => 'Refresh token expiration~~',
'Class:OAuthClient/Attribute:refresh_token_expiration+' => '~~',
'Class:OAuthClient/Attribute:token' => 'Access token~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClient/Attribute:redirect_url' => 'Redirect url~~',
'Class:OAuthClient/Attribute:redirect_url+' => '~~',
'Class:OAuthClient/Attribute:mailbox_list' => 'Mailbox list~~',
'Class:OAuthClient/Attribute:mailbox_list+' => '~~',
]);
//
// Class: OAuthClientAzure
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
]);
//
// Class: OAuthClientGoogle
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
]);

View File

@@ -33,28 +33,28 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Portal:Button:Delete' => '删除',
'Portal:EnvironmentBanner:Title' => '您目前处于 <strong>%1$s</strong> 模式',
'Portal:EnvironmentBanner:GoToProduction' => '回到产品模式',
'Error:HTTP:400' => 'Bad request~~',
'Error:HTTP:401' => '认证',
'Error:HTTP:400' => '请求错误',
'Error:HTTP:401' => '认证错误',
'Error:HTTP:404' => '页面找不到',
'Error:HTTP:500' => 'Oops! 发生了一个错误.',
'Error:HTTP:GetHelp' => '如果问题仍然存在,请联系管理员.',
'Error:XHR:Fail' => '无法加载数据, 请联系管理员',
'Portal:ErrorUserLoggedOut' => '您已退出请重新登录.',
'Portal:ErrorUserLoggedOut' => '您已退出,请重新登录.',
'Portal:Datatables:Language:Processing' => '请稍后...',
'Portal:Datatables:Language:Search' => '过滤器:',
'Portal:Datatables:Language:LengthMenu' => '每页显示 _MENU_ 项',
'Portal:Datatables:Language:ZeroRecords' => '没有结果',
'Portal:Datatables:Language:Info' => '第 _PAGE_ 页,共 _PAGES_ 页',
'Portal:Datatables:Language:InfoEmpty' => '没有信息',
'Portal:Datatables:Language:InfoFiltered' => 'filtered out of _MAX_ items',
'Portal:Datatables:Language:InfoFiltered' => '最多过滤 _MAX_ ',
'Portal:Datatables:Language:EmptyTable' => '表格中没有数据',
'Portal:Datatables:Language:DisplayLength:All' => '全部',
'Portal:Datatables:Language:Paginate:First' => '首页',
'Portal:Datatables:Language:Paginate:Previous' => '上一页',
'Portal:Datatables:Language:Paginate:Next' => '下一页',
'Portal:Datatables:Language:Paginate:Last' => '尾页',
'Portal:Datatables:Language:Sort:Ascending' => '升序排序',
'Portal:Datatables:Language:Sort:Descending' => '降序排序',
'Portal:Datatables:Language:Sort:Ascending' => '升序',
'Portal:Datatables:Language:Sort:Descending' => '降序',
'Portal:Autocomplete:NoResult' => '没有数据',
'Portal:Attachments:DropZone:Message' => '把文件添加为附件',
'Portal:File:None' => '没有文件',
@@ -110,7 +110,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Brick:Portal:Manage:Name' => '管理项目',
'Brick:Portal:Manage:Table:NoData' => '没有项目.',
'Brick:Portal:Manage:Table:ItemActions' => 'Actions',
'Brick:Portal:Manage:Table:ItemActions' => '操作',
'Brick:Portal:Manage:DisplayMode:list' => '列表',
'Brick:Portal:Manage:DisplayMode:pie-chart' => '饼图',
'Brick:Portal:Manage:DisplayMode:bar-chart' => '条形图',
@@ -135,8 +135,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Brick:Portal:Object:Form:Message:ObjectSaved' => '已保存 %1$s~~',
'Brick:Portal:Object:Search:Regular:Title' => '选择 %1$s (%2$s)',
'Brick:Portal:Object:Search:Hierarchy:Title' => '选择 %1$s (%2$s)',
'Brick:Portal:Object:Copy:TextToCopy' => '%1$s: %2$s~~',
'Brick:Portal:Object:Copy:Tooltip' => 'Copy object link~~',
'Brick:Portal:Object:Copy:TextToCopy' => '%1$s: %2$s',
'Brick:Portal:Object:Copy:Tooltip' => '复制对象链接',
'Brick:Portal:Object:Copy:CopiedTooltip' => '已复制'
));

View File

@@ -14,20 +14,18 @@ set_time_limit(0);
if (!defined('APPROOT'))
{
if (file_exists(__DIR__.'/../../../../approot.inc.php'))
{
require_once __DIR__.'/../../../../approot.inc.php'; // When in env-xxxx folder
}
else
{
require_once __DIR__.'/../../../../../approot.inc.php'; // When in datamodels/x.x folder
}
if (file_exists(__DIR__.'/../../../../approot.inc.php')) {
require_once __DIR__ . '/../../../../approot.inc.php'; // When in env-xxxx folder
} else {
require_once __DIR__ . '/../../../../../approot.inc.php'; // When in datamodels/x.x folder
}
}
require_once APPROOT.'lib/autoload.php';
require_once APPROOT . 'lib/autoload.php';
if (!class_exists(Application::class))
{
throw new RuntimeException('You need to add "symfony/framework-bundle" as a Composer dependency.');
require_once APPROOT . 'application/startup.inc.php';
if (!class_exists(Application::class)) {
throw new RuntimeException('You need to add "symfony/framework-bundle" as a Composer dependency.');
}
// Remove --portal_id from CLI params to avoid SF CLI conflicts

View File

@@ -21,7 +21,7 @@
// Disable PhpUnhandledExceptionInspection as the exception handling is made by the file including this one
/** @noinspection PhpUnhandledExceptionInspection */
use Symfony\Component\Debug\Debug;
use Symfony\Component\ErrorHandler\Debug;
use Symfony\Component\Dotenv\Dotenv;
// Global autoloader (portal autoloader is already required through module.itop-portal-base.php)
@@ -43,55 +43,43 @@ if (!defined('MODULESROOT'))
// Load cached env vars if the .env.local.php file exists
// Run "composer dump-env prod" to create it (requires symfony/flex >=1.2)
if (is_array($sEnv = @include dirname(__DIR__).'/.env.local.php'))
{
$_ENV += $sEnv;
}
elseif (!class_exists(Dotenv::class))
{
if (file_exists(dirname(__DIR__).'/.env.local.php')) {
if (is_array($sEnv = @include dirname(__DIR__).'/.env.local.php')) {
$_ENV += $sEnv;
}
} elseif (!class_exists(Dotenv::class)) {
throw new RuntimeException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.');
}
else
{
} else {
$sPath = dirname(__DIR__).'/.env';
$oDotenv = new Dotenv();
$oDotenv->usePutenv();
// load all the .env files
if (method_exists($oDotenv, 'loadEnv'))
{
if (method_exists($oDotenv, 'loadEnv')) {
$oDotenv->loadEnv($sPath);
}
else
{
} else {
// fallback code in case your Dotenv component is not 4.2 or higher (when loadEnv() was added)
if (file_exists($sPath) || !file_exists($sPathDist = "$sPath.dist"))
{
if (file_exists($sPath) || !file_exists($sPathDist = "$sPath.dist")) {
$oDotenv->load($sPath);
}
else
{
} else {
$oDotenv->load($sPathDist);
}
if (null === $sEnv = (isset($_SERVER['APP_ENV']) ? $_SERVER['APP_ENV'] : (isset($_ENV['APP_ENV']) ? $_ENV['APP_ENV'] : null)))
{
if (null === $sEnv = (isset($_SERVER['APP_ENV']) ? $_SERVER['APP_ENV'] : (isset($_ENV['APP_ENV']) ? $_ENV['APP_ENV'] : null))) {
$oDotenv->populate(array('APP_ENV' => $sEnv = 'prod'));
}
if ('test' !== $sEnv && file_exists($sPathDist = "$sPath.local"))
{
if ('test' !== $sEnv && file_exists($sPathDist = "$sPath.local")) {
$oDotenv->load($sPathDist);
$sEnv = isset($_SERVER['APP_ENV']) ? $_SERVER['APP_ENV'] : (isset($_ENV['APP_ENV']) ? $_ENV['APP_ENV'] : $sEnv);
}
if (file_exists($sPathDist = "$sPath.$sEnv"))
{
if (file_exists($sPathDist = "$sPath.$sEnv")) {
$oDotenv->load($sPathDist);
}
if (file_exists($sPathDist = "$sPath.$sEnv.local"))
{
if (file_exists($sPathDist = "$sPath.$sEnv.local")) {
$oDotenv->load($sPathDist);
}
}

View File

@@ -1,10 +1,10 @@
framework:
cache:
# Put the unique name of your app here: the prefix seed
# is used to compute stable namespaces for cache keys.
# Unique name of your app: used to compute stable namespaces for cache keys.
#prefix_seed: your_vendor_name/app_name
# The app cache caches to the filesystem by default.
# The "app" cache stores to the filesystem by default.
# The data in this cache should persist between deploys.
# Other options include:
# Redis
@@ -16,4 +16,4 @@ framework:
# Namespaced pools use the above "app" backend by default
#pools:
#my.dedicated.cache: ~
#my.dedicated.cache: null

View File

@@ -1,3 +0,0 @@
framework:
router:
strict_requirements: true

View File

@@ -1,6 +0,0 @@
web_profiler:
toolbar: true
intercept_redirects: false
framework:
profiler: { only_exceptions: false }

View File

@@ -7,9 +7,25 @@ framework:
# Enables session support. Note that the session will ONLY be started if you read or write from it.
# Remove or comment this section to explicitly disable session support.
session:
handler_id: ~
handler_id: null
cookie_secure: auto
cookie_samesite: lax
storage_factory_id: session.storage.factory.native
#esi: true
#fragments: true
php_errors:
log: true
when@test:
framework:
test: true
profiler: { collect: false }
router: { strict_requirements: true}
session:
storage_factory_id: session.storage.factory.mock_file
when@dev:
framework:
profiler: { only_exceptions: false }
router: { strict_requirements: true}

View File

@@ -1,3 +1,17 @@
framework:
router:
strict_requirements: ~
utf8: true
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
#default_uri: http://localhost
when@prod:
framework:
router:
strict_requirements: null
when@dev:
framework:
router:
strict_requirements: true

View File

@@ -1,4 +0,0 @@
framework:
test: true
session:
storage_id: session.storage.mock_file

View File

@@ -1,3 +0,0 @@
framework:
router:
strict_requirements: true

View File

@@ -1,6 +0,0 @@
web_profiler:
toolbar: false
intercept_redirects: false
framework:
profiler: { collect: false }

View File

@@ -2,3 +2,7 @@ twig:
default_path: '%combodo.modules.absolute_path%'
debug: '%kernel.debug%'
strict_variables: '%kernel.debug%'
when@test:
twig:
strict_variables: true

View File

@@ -0,0 +1,12 @@
when@dev:
web_profiler:
toolbar: true
intercept_redirects: false
when@test:
web_profiler:
toolbar: false
intercept_redirects: false

View File

@@ -1,3 +0,0 @@
_errors:
resource: '@TwigBundle/Resources/config/routing/errors.xml'
prefix: /_error

View File

@@ -1,7 +0,0 @@
web_profiler_wdt:
resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml'
prefix: /_wdt
web_profiler_profiler:
resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml'
prefix: /_profiler

View File

@@ -0,0 +1,4 @@
when@dev:
_errors:
resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
prefix: /_error

View File

@@ -0,0 +1,8 @@
when@dev:
web_profiler_wdt:
resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml'
prefix: /_wdt
web_profiler_profiler:
resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml'
prefix: /_profiler

View File

@@ -24,8 +24,6 @@ imports:
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
# Replace default url generator service
router.options.generator_base_class: Combodo\iTop\Portal\Routing\UrlGenerator
# Used in templates
combodo.current_environment: '%env(string:COMBODO_CURRENT_ENVIRONMENT)%'
@@ -100,17 +98,19 @@ services:
- '@Combodo\iTop\Portal\Twig\AppVariable.inner'
- '@service_container'
Combodo\iTop\Portal\Routing\UrlGenerator:
decorates: 'router'
arguments: ['@Combodo\iTop\Portal\Routing\UrlGenerator.inner']
# Standard services
combodo.current_contact.photo_url:
public: true
class: Combodo\iTop\Portal\VariableAccessor\CombodoCurrentContactPhotoUrl
arguments: ['@combodo.current_user', '@service_container']
# Note: This service is initialized with a UserLocal object as it needs a class that can be instantiated.
# Anyway, it will be replaced with the real class by UserProvider in onKernelRequestEvent.
# Note: Services relying on this one should use \User in their signature and not \UserLocal.
arguments: ['@Combodo\iTop\Portal\EventListener\UserProvider', '@service_container']
combodo.current_user:
alias: Combodo\iTop\Portal\Twig\CurrentUserAccessor
public: true
class: UserLocal
# Aliases
brick_collection:

View File

@@ -20,7 +20,7 @@
namespace Combodo\iTop\Portal\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use \Symfony\Bundle\FrameworkBundle\Controller\AbstractController as SymfonyAbstractController;
/**
* Class AbstractController
@@ -29,8 +29,37 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.3.0
*/
abstract class AbstractController extends Controller
abstract class AbstractController extends SymfonyAbstractController
{
/**
* Return services needed inside controllers.
* Allow access to service via $controller->get(`service_name`).
*
* Improvement: Use service dependency injection
*
* @return array array of service injected to controllers
* @since 3.1.0
*
*/
public static function getSubscribedServices(): array
{
return array_merge(parent::getSubscribedServices(), [
'brick_collection' => 'Combodo\iTop\Portal\Brick\BrickCollection',
'request_manipulator' => 'Combodo\iTop\Portal\Helper\RequestManipulatorHelper',
'scope_validator' => 'Combodo\iTop\Portal\Helper\ScopeValidatorHelper',
'security_helper' => 'Combodo\iTop\Portal\Helper\SecurityHelper',
'context_manipulator' => 'Combodo\iTop\Portal\Helper\ContextManipulatorHelper',
'navigation_rule_helper' => 'Combodo\iTop\Portal\Helper\NavigationRuleHelper',
'ui_extensions_helper' => 'Combodo\iTop\Portal\Helper\UIExtensionsHelper',
'lifecycle_validator' => 'Combodo\iTop\Portal\Helper\LifecycleValidatorHelper',
'url_generator' => 'router',
'object_form_handler' => 'Combodo\iTop\Portal\Helper\ObjectFormHandlerHelper',
'browse_brick' => 'Combodo\iTop\Portal\Helper\BrowseBrickHelper',
'brick_controller_helper' => 'Combodo\iTop\Portal\Helper\BrickControllerHelper',
'session_message_helper' => 'Combodo\iTop\Portal\Helper\SessionMessageHelper',
]);
}
/**
* Unlike {@see \Symfony\Bundle\FrameworkBundle\Controller\ControllerTrait::redirectToRoute()}, this method directly calls the route controller without creating a redirection client side
*

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