Compare commits

...

103 Commits

Author SHA1 Message Date
Timothee
d0d4f11146 N°7662 Allowing indentation and de-indentation 2025-01-21 11:07:10 +01:00
jf-cbd
5ce1788d4a N°7776 remove twig from ajax calls, 3.2 edition 2025-01-20 16:34:46 +01:00
jf-cbd
38fe31c9fc Merge remote-tracking branch 'origin/support/3.1' into support/3.2
# Conflicts:
#	datamodels/2.x/itop-portal-base/portal/src/Controller/UserProfileBrickController.php
#	datamodels/2.x/itop-portal-base/portal/src/Form/ObjectFormManager.php
2025-01-20 16:33:35 +01:00
jf-cbd
ec61b52238 N°7776 remove twig from ajax calls, 3.1 edition 2025-01-20 16:02:26 +01:00
jf-cbd
072596a53b Merge remote-tracking branch 'origin/support/2.7' into support/3.1
# Conflicts:
#	datamodels/2.x/itop-portal-base/portal/src/Form/ObjectFormManager.php
2025-01-20 15:53:34 +01:00
jf-cbd
160bfd714b N°7776 remove twig from ajax calls 2025-01-20 15:41:22 +01:00
Eric Espie
3b51124f1c N°7927 - No context tag available on designer MTP 2025-01-17 10:06:20 +01:00
jf-cbd
19fa836758 Merge remote-tracking branch 'origin/support/3.1' into support/3.2 2025-01-16 17:16:31 +01:00
jf-cbd
1c5cb1547f Merge remote-tracking branch 'origin/support/2.7' into support/3.1 2025-01-16 17:15:12 +01:00
jf-cbd
8d58372074 Update unattended installation script documentation 2025-01-16 17:13:26 +01:00
Eric Espie
e98c6637ac N°8108 - EVENT_DB_AFTER_WRITE: $oEventData->Get('changes') missing previous values 2025-01-16 09:31:12 +01:00
odain
7d2a9d0bfc N°8066 - Polishing Webhook Oauth 2025-01-15 17:26:12 +01:00
odain
762d1162ca N°8066 - Polishing Webhook Oauth 2025-01-15 16:59:51 +01:00
odain
95dbe4c859 N°7873 - ci fix remove useless require_once 2025-01-14 07:52:07 +01:00
Benjamin Dalsass
ec6adee9c1 Remove useless require_once and replace it with inheritance 2025-01-13 14:32:06 +01:00
Benjamin Dalsass
baa8bba926 N°8031 - Make all portal bricks use custom templates for all templates
add missing templates
2025-01-13 12:50:58 +01:00
v-dumas
8dc5411717 N°7906 - User Preference: friendlyname, list, search criteria and reconciliation 2025-01-13 12:08:14 +01:00
Benjamin Dalsass
f1d448fd78 N°8031 - Make all portal bricks use custom templates for all templates
add missing templates
2025-01-13 11:53:44 +01:00
odain
a4490e2b5f N°7873 - Portal: Brick visible despite XML security tag allowed profiles 2025-01-13 11:06:27 +01:00
odain
efb7831a5a N°7111 - False link at the end of the setup 2025-01-13 08:30:23 +01:00
Benjamin Dalsass
9fadbb5eb1 N°8031 - Make all portal bricks use custom templates for all templates (#696)
Service implementation
2025-01-13 08:04:49 +01:00
Romain Quetiez
93dba0644d N°5791 - Handle NOT IN and NOT LIKE too 2025-01-10 16:21:12 +01:00
XGUI
ec324bb28e N°7746 - Caselog edition button active even if the user has a read-only access to the object 2025-01-10 11:12:03 +01:00
Eric Espie
dc8f521b12 N°7145 - UI - Init Value DateTime and Date with Day Time (Add default values on mandatory dates) 2025-01-09 11:56:55 +01:00
Eric Espie
bf6277fcd2 N°7145 - UI - Init Value DateTime and Date with Day Time (support raw date values) 2025-01-09 11:22:28 +01:00
Eric Espie
886db5d6ad N°7145 - UI - Init Value DateTime and Date with Day Time (use OQL syntax for default value) 2025-01-09 10:49:35 +01:00
Eric Espie
0e8ddf990c N°7145 - UI - Init Value DateTime and Date with Day Time (Fix Event class) 2025-01-07 13:21:13 +01:00
Eric Espie
346a8eadec N°5791 - Obsolescence condition containing IN makes object creation fail 2025-01-07 11:29:33 +01:00
Eric Espie
6948c594c2 N°7145 - UI - Init Value DateTime and Date with Day Time 2025-01-07 10:18:23 +01:00
Eric Espie
301a7a92a0 N°7145 - UI - Init Value DateTime and Date with Day Time 2025-01-06 16:52:32 +01:00
Eric Espie
73bb80ebea N°7206 - Force DBUpdate() when a transition is asked, and it leads to the same state 2025-01-06 11:31:36 +01:00
Timmy38
1e674d7bdc N°7383 Show data table even when there is no data after filtering (#695) 2025-01-06 11:06:18 +01:00
v-dumas
1225ee1e78 improve test 2025-01-03 17:18:24 +01:00
v-dumas
a91de9fb36 Add helpers for stopwatches manipulation 2025-01-03 17:04:41 +01:00
v-dumas
71b3a415a6 N°7206 - Add tests 2025-01-03 16:17:51 +01:00
Romain Quetiez
b97c7433c8 🎨 N°7633 Cosmetics on unit tests 2025-01-03 11:57:51 +01:00
jf-cbd
11fc958a7b 🐛 N°6284 - Add data-object-key 2024-12-31 15:01:36 +01:00
odain
a151e40b75 Merge branch 'support/3.1' into support/3.2 2024-12-27 11:13:50 +01:00
odain
5780f26817 N°7810: fix merge 2024-12-27 11:13:31 +01:00
odain
9a690861a3 Merge branch 'support/3.1' into support/3.2 2024-12-27 09:24:33 +01:00
odain
343f3286b8 Merge branch 'support/2.7' into support/3.1 2024-12-27 09:08:47 +01:00
Eric Espie
37fc1a5723 N°7810 - security hardening 2024-12-27 09:04:28 +01:00
Eric Espie
7a09b3effc 🐛 Don't display create mailbox if the corresponding class does not exist 2024-12-24 15:05:48 +01:00
Romain Quetiez
4f6d514694 N°8001 - Refactoring: instantiation of an ormDocument moved to... ormDocument 2024-12-20 10:36:25 +01:00
Stephen Abello
8f8b65a71d N°8031 - Add robustness if portal configuration doesn't go through 2024-12-20 10:15:22 +01:00
Timothee
49e72e83fe N°6282 Fix XSS vulnerability in wsdl 2024-12-19 15:34:43 +01:00
Stephen Abello
f0685e33e1 N°8031 - Add robustness and fix SF parameter binding being ambiguous in extensions bricks 2024-12-19 15:14:46 +01:00
Timmy38
42f391472b N°6282 Fix XSS vulnerability in soap (#690)
* N°6282 Fix XSS vulnerability in soap
2024-12-19 11:39:00 +01:00
Eric Espie
30ef2735b6 N°8001 - TriggerOnObjectMention : load of the icon failed 2024-12-18 16:03:39 +01:00
Stephen Abello
bbff0b72d3 N°8031 - Make all portal bricks use custom templates for all templates (#691)
* N°8031 - Make all portal bricks use custom templates for all templates

* Rename parameter following code review

* Add const variables following code review

* Modify method name following code review
2024-12-18 11:09:39 +01:00
jf-cbd
2dffab9ca0 🌐 Update ZH CN dictionaries 2024-12-18 10:39:25 +01:00
jf-cbd
1cbfa4f1b1 🌐 Update ZH CN dictionaries 2024-12-18 10:11:52 +01:00
odain-cbd
5f85757630 N°7633 - Reloads the same user multiple times if it no longer exists (#692)
* N°7633 - Reloads the same user multiple times if it no longer exists

* Update core/userrights.class.inc.php

good catch

Co-authored-by: Thomas Casteleyn <thomas.casteleyn@super-visions.com>

* Update core/userrights.class.inc.php

good catch (again)

Co-authored-by: Thomas Casteleyn <thomas.casteleyn@super-visions.com>

* Update core/userrights.class.inc.php

Co-authored-by: Thomas Casteleyn <thomas.casteleyn@super-visions.com>

* PR feedbacks from Romain

* ci: rename user logins

---------

Co-authored-by: Thomas Casteleyn <thomas.casteleyn@super-visions.com>
2024-12-17 17:27:49 +01:00
v-dumas
56d3ac668c N°8047 - SuperUser profile moved under iTop Community 3.2.1 2024-12-17 16:31:59 +01:00
jf-cbd
0a3b02bf45 🌐 Update ZH CN dictionaries 2024-12-16 18:30:22 +01:00
jf-cbd
74ebbc5fa4 🌐 Update ZH CN dictionaries 2024-12-16 18:19:17 +01:00
Eric Espie
a762b6a2bb Fix failing directory removal 2024-12-16 17:04:33 +01:00
Eric Espie
32ef639ce1 N°7803 - MTP from itophub/designer failing in itop 3.2.0 2024-12-16 16:44:59 +01:00
Purple Grape
8647a76dbf 🌐 Translations - improved translation for zh cn 20241108 (#679)
* improved translation for zh cn
2024-12-16 11:39:26 +01:00
jf-cbd
47cd8bce31 Security hardening 2024-12-16 11:05:16 +01:00
jf-cbd
86c677b2ca Merge remote-tracking branch 'origin/support/3.1' into support/3.2
# Conflicts:
#	datamodels/2.x/itop-portal-base/portal/src/Controller/ObjectController.php
2024-12-16 11:02:37 +01:00
Eric Espie
960129316d N°8050 - Fix regression due to directories filter changes 2024-12-16 10:56:06 +01:00
jf-cbd
1fa50f695d Security hardening 2024-12-16 10:47:06 +01:00
jf-cbd
692cf4f635 Merge branch 'support/2.7' into support/3.1 2024-12-16 10:27:00 +01:00
jf-cbd
95aa444ee6 Security hardening 2024-12-13 16:48:13 +01:00
jf-cbd
f5de808c7c Security hardening (#685)
* security hardening
2024-12-13 15:09:18 +01:00
Eric Espie
fc388313d7 N°8050 - Problems with interface discovery from itop 2024-12-13 10:14:17 +01:00
odain
d544ee5498 N°7750 - ci enhance test 2024-12-13 09:35:35 +01:00
odain
ce187550f6 N°7750 - Fix display regression 2024-12-12 12:21:57 +01:00
Eric Espie
5d15a08824 🥅 Fast setup error display 2024-12-12 09:55:16 +01:00
odain
8135316119 N°7750 - Bug with OQL set as Shortcut 2024-12-11 16:05:15 +01:00
Eric Espie
868c0ae836 N°7997 - Sharing Base incompatible with iTop >= 3.1 (code review) 2024-12-11 15:51:36 +01:00
Eric Espie
d03d4fce5f N°7997 - Sharing Base incompatible with iTop >= 3.1 2024-12-11 13:35:15 +01:00
Eric Espie
aa55c2b30f N°7997 - Sharing Base incompatible with iTop >= 3.1 2024-12-11 13:28:37 +01:00
Eric Espie
9d3b46b919 🥅 Fast setup error display 2024-12-11 11:40:03 +01:00
Eric Espie
01b4dbba71 🥅 Fast setup error display 2024-12-11 11:20:32 +01:00
Eric Espie
72ac4096c1 N°7854 - ⬆️ Bump twig version 2024-12-10 17:08:48 +01:00
Eric Espie
19559b08a7 N°7854 - ⬆️ Bump twig version 2024-12-10 10:52:30 +01:00
Eric Espie
346564ca0e N°7854 - ⬆️ Bump twig version 2024-12-10 10:11:28 +01:00
Eric Espie
1bf53bae2a N°7871 - unable to migrate to itop3.2 if a trigger on object mention without "mentioned filter" exists 2024-12-09 17:05:07 +01:00
Eric Espie
29ce042916 N°7867 - Issue with MTP offline (reset cache in metamodel) 2024-12-09 10:38:50 +01:00
odain
83539d6d4c N°7446 - Make ItopCustomDatamodelTestCase work with modules in production-modules 2024-12-05 11:29:05 +01:00
Eric Espie
e6a7b926f6 N°7852 - Issue on Class groups definition when checking EventNotification class 2024-12-05 11:14:19 +01:00
Eric Espie
b30e053236 N°8020 - Bugs MFA and designer incompatibility 2024-12-03 16:42:27 +01:00
Stephen Abello
afd96a0f49 N°7995 - Allow to redefine portal twig template for all bricks in a portal (#686)
* N°7995 - Allow to redefine portal twig template for all bricks in a portal

* Apply modifications from code review

* Fix variable name

* Apply changes from code review
2024-12-03 10:44:37 +01:00
Eric Espie
a77765ec7b N°8019 - Enrich event with transition information 2024-12-03 10:28:13 +01:00
jf-cbd
64b4b03ea9 Security hardening 2024-12-03 10:26:11 +01:00
jf-cbd
a797878b17 Security hardening 2024-12-03 09:54:31 +01:00
jf-cbd
1fa0f7bdd9 N°8007 - Security hardening 2024-12-02 17:45:39 +01:00
Eric Espie
f718b4173d N°7206 - TriggerOnStateEnter not called when using reassign transition (after review) 2024-12-02 17:28:15 +01:00
Eric Espie
e057c0f081 N°7777 - Click on tab "Last executions" during action creation crashs the form 2024-12-02 17:12:32 +01:00
Eric Espie
5a49fc7654 N°7206 - TriggerOnStateEnter not called when using reassign transition 2024-12-02 14:49:28 +01:00
Stephen Abello
6fca659c9d Fix portal not being able to use $common-* SCSS variables when recompiling stylesheets 2024-12-02 14:06:53 +01:00
Stephen Abello
eacd08f31e Fix SCSS comments type 2024-12-02 14:03:39 +01:00
jf-cbd
5f7d8f6cc0 Merge remote-tracking branch 'origin/support/3.1' into support/3.2 2024-11-29 16:43:13 +01:00
jf-cbd
cbb4281a37 N°7980 - security hardening 2024-11-29 16:40:34 +01:00
odain
d7a8d335d5 N°7446 - Fix in CI environment when class already loaded 2024-11-29 12:22:38 +01:00
odain
bd1d447677 N°7446 - Fix in CI environment 2024-11-29 12:08:16 +01:00
Eric Espie
bb405d5173 N°7429 - Create an MFA extension for iTop - Add support for AttributeClassSet 2024-11-27 14:57:51 +01:00
Benjamin Dalsass
4723fc885c Merge remote-tracking branch 'origin/support/3.1' into support/3.2
# Conflicts:
#	application/dashboard.class.inc.php
2024-11-27 09:55:15 +01:00
Benjamin Dalsass
06dcae1dd1 Merge remote-tracking branch 'origin/support/2.7' into support/3.1 2024-11-27 09:50:57 +01:00
Benjamin Dalsass
e03033ce52 N°7219 - Fatal error following dashboard modification when dashboard title contains an é 2024-11-27 09:40:22 +01:00
Timothee
19eae916f0 N°7792 Do not initialize CAS if already started 2024-11-22 09:59:41 +01:00
403 changed files with 17406 additions and 8441 deletions

View File

@@ -825,49 +825,38 @@ class UserRightsProfile extends UserRightsAddOnAPI
{
// We are protected by GetSelectFilter: the object set contains objects allowed or shared for reading
// We have to answer NO for objects shared for reading purposes
if (self::HasSharing())
{
$aClassProps = SharedObject::GetSharedClassProperties($sClass);
if ($aClassProps)
{
// This class is shared, GetSelectFilter may allow some objects for read only
// But currently we are checking wether the objects might be written...
// Let's exclude the objects based on the relevant criteria
if (self::HasSharing() && SharedObject::GetSharedClassProperties($sClass)) {
// This class is shared, GetSelectFilter may allow some objects for read only
// But currently we are checking whether the objects might be written...
// Let's exclude the objects based on the relevant criteria
$sOrgAttCode = self::GetOwnerOrganizationAttCode($sClass);
if (!is_null($sOrgAttCode))
{
$aUserOrgs = $this->GetUserOrgs($oUser, $sClass);
if (!is_null($aUserOrgs) && count($aUserOrgs) > 0)
{
$iCountNO = 0;
$iCountYES = 0;
$oInstanceSet->Rewind();
while($oObject = $oInstanceSet->Fetch())
{
$iOrg = $oObject->Get($sOrgAttCode);
if (in_array($iOrg, $aUserOrgs))
{
$iCountYES++;
}
else
{
$iCountNO++;
}
}
if ($iCountNO == 0)
{
$iPermission = UR_ALLOWED_YES;
}
elseif ($iCountYES == 0)
{
$iPermission = UR_ALLOWED_NO;
}
else
{
$iPermission = UR_ALLOWED_DEPENDS;
// Use $oInstanceSet only if sClass is the main class
if (!is_a($oInstanceSet->GetClass(), $sClass, true)) {
/** @var \DBObjectSet $oInstanceSet */
throw new CoreException(__FUNCTION__.': Expecting object set to be of class '.$sClass.' but it is of class '.$oInstanceSet->GetClass(), ['OQL_Query' => $oInstanceSet->GetFilter()->ToOQL(), 'classes' => $oInstanceSet->GetSelectedClasses()]);
}
$sOrgAttCode = self::GetOwnerOrganizationAttCode($sClass);
if (!is_null($sOrgAttCode)) {
$aUserOrgs = $this->GetUserOrgs($oUser, $sClass);
if (!is_null($aUserOrgs) && count($aUserOrgs) > 0) {
$iCountNO = 0;
$iCountYES = 0;
$oInstanceSet->Rewind();
while ($oObject = $oInstanceSet->Fetch()) {
$iOrg = $oObject->Get($sOrgAttCode);
if (in_array($iOrg, $aUserOrgs)) {
$iCountYES++;
} else {
$iCountNO++;
}
}
if ($iCountNO == 0) {
$iPermission = UR_ALLOWED_YES;
} elseif ($iCountYES == 0) {
$iPermission = UR_ALLOWED_NO;
} else {
$iPermission = UR_ALLOWED_DEPENDS;
}
}
}
}
@@ -982,4 +971,3 @@ class UserRightsProfile extends UserRightsAddOnAPI
UserRights::SelectModule('UserRightsProfile');
?>

View File

@@ -3439,8 +3439,18 @@ EOF
}
$sInputType = '';
$sInputId = 'att_'.$iFieldIndex;
$value = $this->Get($sAttCode);
$sDisplayValue = $this->GetEditValue($sAttCode);
if ($oAttDef instanceof AttributeDateTime && !$oAttDef->IsNullAllowed() && $value === $oAttDef->GetNullValue()) {
$value = $oAttDef->GetDefaultValue($this);
if ($value !== $oAttDef->GetNullValue()) {
// Set default date
$this->Set($sAttCode, $value);
$sDisplayValue = $this->GetEditValue($sAttCode);
}
}
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef,
$this->Get($sAttCode), $this->GetEditValue($sAttCode), $sInputId, '', $iExpectCode,
$value, $sDisplayValue, $sInputId, '', $iExpectCode,
$aArgs, true, $sInputType);
$aAttrib = array(
'label' => '<span>'.$oAttDef->GetLabel().'</span>',
@@ -5923,14 +5933,14 @@ JS
*
* @since 3.1.0
*/
final protected function FireEventCheckToWrite(): void
final protected function FireEventCheckToWrite(?string $sStimulusBeingApplied): void
{
$this->FireEvent(EVENT_DB_CHECK_TO_WRITE, ['is_new' => $this->IsNew()]);
$this->FireEvent(EVENT_DB_CHECK_TO_WRITE, ['is_new' => $this->IsNew(), 'stimulus_applied' => $sStimulusBeingApplied]);
}
final protected function FireEventBeforeWrite()
final protected function FireEventBeforeWrite(?string $sStimulusBeingApplied)
{
$this->FireEvent(EVENT_DB_BEFORE_WRITE, ['is_new' => $this->IsNew()]);
$this->FireEvent(EVENT_DB_BEFORE_WRITE, ['is_new' => $this->IsNew(), 'stimulus_applied' => $sStimulusBeingApplied]);
}
/**
@@ -5942,11 +5952,11 @@ JS
* @throws \CoreException
* @since 3.1.0
*/
final protected function FireEventAfterWrite(array $aChanges, bool $bIsNew): void
final protected function FireEventAfterWrite(array $aChanges, bool $bIsNew, ?string $sStimulusBeingApplied): void
{
$this->NotifyAttachedObjectsOnLinkClassModification();
$this->RemoveObjectAwaitingEventDbLinksChanged(get_class($this), $this->GetKey());
$this->FireEvent(EVENT_DB_AFTER_WRITE, ['is_new' => $bIsNew, 'changes' => $aChanges]);
$this->FireEvent(EVENT_DB_AFTER_WRITE, ['is_new' => $bIsNew, 'changes' => $aChanges, 'stimulus_applied' => $sStimulusBeingApplied]);
}
//////////////
@@ -6179,9 +6189,9 @@ JS
* @inheritDoc
* @throws \CoreException
*/
final protected function FireEventComputeValues(): void
final protected function FireEventComputeValues(?string $sStimulusBeingApplied): void
{
$this->FireEvent(EVENT_DB_COMPUTE_VALUES);
$this->FireEvent(EVENT_DB_COMPUTE_VALUES, ['is_new' => $this->IsNew(), 'stimulus_applied' => $sStimulusBeingApplied]);
}
/**

View File

@@ -1266,13 +1266,12 @@ EOF
$sOkButtonLabel = Dict::S('UI:Button:Save');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$sId = utils::HtmlEntities($this->sId);
$sLayoutClass = utils::HtmlEntities($this->sLayoutClass);
$sId = json_encode($this->sId);
$sLayoutClass = json_encode($this->sLayoutClass);
$sAutoReload = $this->bAutoReload ? 'true' : 'false';
$sAutoReloadSec = (string) $this->iAutoReloadSec;
$sTitle = utils::HtmlEntities($this->sTitle);
$sFile = utils::HtmlEntities($this->GetDefinitionFile());
$sFileForJS = json_encode($this->GetDefinitionFile());
$sTitle = json_encode($this->sTitle);
$sFile = json_encode($this->GetDefinitionFile());
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
$sReloadURL = $this->GetReloadURL();
@@ -1328,15 +1327,15 @@ $('#dashboard_editor').dialog({
});
$('#dashboard_editor .ui-layout-center').runtimedashboard({
dashboard_id: '$sId',
layout_class: '$sLayoutClass',
title: '$sTitle',
dashboard_id: $sId,
layout_class: $sLayoutClass,
title: $sTitle,
auto_reload: $sAutoReload,
auto_reload_sec: $sAutoReloadSec,
submit_to: '$sUrl',
submit_parameters: {operation: 'save_dashboard', file: {$sFileForJS}, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
submit_parameters: {operation: 'save_dashboard', file: $sFile, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
render_to: '$sUrl',
render_parameters: {operation: 'render_dashboard', file: {$sFileForJS}, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
render_parameters: {operation: 'render_dashboard', file: $sFile, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
new_dashlet_parameters: {operation: 'new_dashlet'}
});

View File

@@ -238,6 +238,10 @@ The object can be modified.]]></description>
<description>Creation flag</description>
<type>boolean</type>
</event_datum>
<event_datum id="stimulus_applied">
<description>Life cycle stimulus applied (null if not within a transition)</description>
<type>string</type>
</event_datum>
<event_datum id="debug_info">
<description>Debug string</description>
<type>string</type>
@@ -263,6 +267,10 @@ Call $this->AddCheckWarning($sWarningMessage) to display a warning.
<description>Creation flag</description>
<type>boolean</type>
</event_datum>
<event_datum id="stimulus_applied">
<description>Life cycle stimulus applied (null if not within a transition)</description>
<type>string</type>
</event_datum>
<event_datum id="debug_info">
<description>Debug string</description>
<type>string</type>
@@ -290,6 +298,10 @@ The modifications can be propagated to other objects.]]></description>
<description><![CDATA[For updates, the list of changes done during this operation]]></description>
<type>array</type>
</event_datum>
<event_datum id="stimulus_applied">
<description>Life cycle stimulus applied (null if not within a transition)</description>
<type>string</type>
</event_datum>
<event_datum id="debug_info">
<description>Debug string</description>
<type>string</type>
@@ -420,6 +432,14 @@ The only action allowed is to deny transitions with $this->DenyTransition($sTran
<description>The object inserted</description>
<type>DBObject</type>
</event_datum>
<event_datum id="is_new">
<description>Creation flag</description>
<type>boolean</type>
</event_datum>
<event_datum id="stimulus_applied">
<description>Life cycle stimulus applied (null if not within a transition)</description>
<type>string</type>
</event_datum>
<event_datum id="debug_info">
<description>Debug string</description>
<type>string</type>

View File

@@ -2024,8 +2024,8 @@ class MenuBlock extends DisplayBlock
$sSelectedClassName = MetaModel::GetName($sSelectedClass);
// Check rights on class
$bIsBulkModifyAllowed = (!MetaModel::IsAbstract($sSelectedClass)) && UserRights::IsActionAllowed($sSelectedClass, UR_ACTION_BULK_MODIFY, $oSet) && ($oReflectionClass->IsSubclassOf('cmdbAbstractObject'));
$bIsBulkDeleteAllowed = (bool) UserRights::IsActionAllowed($sSelectedClass, UR_ACTION_BULK_DELETE, $sSelectedClass);
$bIsBulkModifyAllowed = (!MetaModel::IsAbstract($sSelectedClass)) && UserRights::IsActionAllowed($sSelectedClass, UR_ACTION_BULK_MODIFY) && ($oReflectionClass->IsSubclassOf('cmdbAbstractObject'));
$bIsBulkDeleteAllowed = (bool) UserRights::IsActionAllowed($sSelectedClass, UR_ACTION_BULK_DELETE);
// Refine filter on selected class so bullk actions occur on the right class
$oSelectedClassFilter = $this->GetFilter()->DeepClone();

View File

@@ -1159,11 +1159,11 @@ class OQLMenuNode extends MenuNode
{
$sUsageId = utils::GetSafeId($sUsageId);
$oSearch = DBObjectSearch::FromOQL($sOql);
$sClass= $oSearch->GetClass();
$sClass= $oSearch->GetClass();
$sIcon = MetaModel::GetClassIcon($sClass, false);
if ($bSearchPane) {
$aParams = array_merge(['open' => $bSearchOpen, 'table_id' => $sUsageId, 'submit_on_load' => false], $aExtraParams);
$oBlock = new DisplayBlock($oSearch, 'search', false /* Asynchronous */, $aParams);
$oBlock = new DisplayBlock($oSearch, DisplayBlock::ENUM_STYLE_SEARCH, false /* Asynchronous */, $aParams);
$oBlock->Display($oPage, 0);
$oPage->add("<div class='sf_results_area ibo-add-margin-top-250' data-target='search_results'>");
}

View File

@@ -249,9 +249,9 @@ class appUserPreferences extends DBObject
(
"category" => "gui",
"key_type" => "autoincrement",
"name_attcode" => "userid",
"name_attcode" => "login",
"state_attcode" => "",
"reconc_keys" => array("userid"),
"reconc_keys" => array("userid","login"),
"db_table" => "priv_app_preferences",
"db_key_field" => "id",
"db_finalclass_field" => "",
@@ -260,8 +260,10 @@ class appUserPreferences extends DBObject
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributePropertySet("preferences", array("allowed_values"=>null, "sql"=>"preferences", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_SetZListItems('list', array('preferences',));
MetaModel::Init_SetZListItems('default_search', array('userid'));
MetaModel::Init_AddAttribute(new AttributeExternalField("org_id", array("allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "org_id")));
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login")));
MetaModel::Init_SetZListItems('list', array('org_id','preferences'));
MetaModel::Init_SetZListItems('default_search', array('userid','login','org_id'));
}
/**

View File

@@ -180,6 +180,7 @@ class utils
*/
private static $sAbsoluteUrlAppRootCache = null;
protected static function LoadParamFile($sParamFile)
{
if (!file_exists($sParamFile)) {
@@ -1451,9 +1452,12 @@ class utils
* @return string A path to a folder into which any module can store cache data
* The corresponding folder is created or cleaned upon code compilation
*/
public static function GetCachePath()
public static function GetCachePath(string $sEnvironment = null): string
{
return static::GetDataPath().'cache-'.MetaModel::GetEnvironment().'/';
if (is_null($sEnvironment)) {
$sEnvironment = MetaModel::GetEnvironment();
}
return static::GetDataPath()."cache-$sEnvironment/";
}
/**
@@ -2390,53 +2394,75 @@ SQL;
return $bRet;
}
/**
* @param $sPath
*
* @return false|\ormDocument
* @throws \Exception
*
* @deprecated 3.2.1 use utils::GetDocumentFromSelfURL instead
*/
public static function IsSelfURL($sPath)
{
return self::GetDocumentFromSelfURL($sPath);
}
/**
* Check if the given URL is a link to download a document/image on the CURRENT iTop
* In such a case we can read the content of the file directly in the database (if the users rights allow) and return the ormDocument
*
* @Since 3.2.1 a local URL is transformed into a local file to read
*
* @param string $sPath
* @return false|ormDocument
* @throws Exception
*/
public static function IsSelfURL($sPath)
public static function GetDocumentFromSelfURL(string $sPath)
{
$result = false;
$sPageUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.document.php';
if (substr($sPath, 0, strlen($sPageUrl)) == $sPageUrl)
{
if (utils::StartsWith($sPath, $sPageUrl)) {
// If the URL is an URL pointing to this instance of iTop, then
// extract the "query" part of the URL and analyze it
$sQuery = parse_url($sPath, PHP_URL_QUERY);
if ($sQuery !== null)
{
if ($sQuery !== null) {
$aParams = array();
foreach(explode('&', $sQuery) as $sChunk)
{
foreach (explode('&', $sQuery) as $sChunk) {
$aParts = explode('=', $sChunk ?? '');
if (count($aParts) != 2) continue;
if (count($aParts) != 2) {
continue;
}
$aParams[$aParts[0]] = urldecode($aParts[1]);
}
$result = array_key_exists('operation', $aParams) && array_key_exists('class', $aParams) && array_key_exists('id', $aParams) && array_key_exists('field', $aParams) && ($aParams['operation'] == 'download_document');
if ($result)
{
if ($result) {
// This is a 'download_document' operation, let's retrieve the document directly from the database
$sClass = $aParams['class'];
$iKey = $aParams['id'];
$sAttCode = $aParams['field'];
$oObj = MetaModel::GetObject($sClass, $iKey, false /* must exist */); // Users rights apply here !!
if ($oObj)
{
if ($oObj) {
/**
* @var ormDocument $result
*/
$result = clone $oObj->Get($sAttCode);
return $result;
return clone $oObj->Get($sAttCode);
}
}
}
throw new Exception('Invalid URL. This iTop URL is not pointing to a valid Document/Image.');
}
return $result;
if (utils::StartsWith($sPath, utils::GetAbsoluteUrlAppRoot())) {
$sFilePath = utils::LocalPath(APPROOT.substr($sPath, strlen(utils::GetAbsoluteUrlAppRoot())));
if (false === $sFilePath) {
return false;
}
$sFilePath = APPROOT.$sFilePath;
return ormDocument::FromFile($sFilePath);
}
return false;
}
/**
@@ -2444,68 +2470,28 @@ SQL;
* - an URL pointing to a blob (image/document) on the current iTop server
* - an http(s) URL
* - the local file system (but only if you are an administrator)
* @param string $sPath
*
* @param string|null $sPath
* @return ormDocument|null
* @throws Exception
*/
public static function FileGetContentsAndMIMEType($sPath)
{
$oUploadedDoc = null;
$aKnownExtensions = array(
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'gif' => 'image/gif',
'png' => 'image/png',
'pdf' => 'application/pdf',
'doc' => 'application/msword',
'dot' => 'application/msword',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',
'vsd' => 'application/x-visio',
'vdx' => 'application/visio.drawing',
'odt' => 'application/vnd.oasis.opendocument.text',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
'odp' => 'application/vnd.oasis.opendocument.presentation',
'zip' => 'application/zip',
'txt' => 'text/plain',
'htm' => 'text/html',
'html' => 'text/html',
'exe' => 'application/octet-stream',
);
$sData = null;
$sMimeType = 'text/plain'; // Default MIME Type: treat the file as a bunch a characters...
$sFileName = 'uploaded-file'; // Default name for downloaded-files
$sExtension = '.txt'; // Default file extension in case we don't know the MIME Type
if(empty($sPath))
{
if (utils::IsNullOrEmptyString($sPath)) {
// Empty path (NULL or '') means that there is no input, making an empty document.
$oUploadedDoc = new ormDocument('', '', '');
return new ormDocument('', '', '');
}
elseif (static::IsURL($sPath))
{
if ($oUploadedDoc = static::IsSelfURL($sPath))
{
// Nothing more to do, we've got it !!
if (static::IsURL($sPath)) {
$oUploadedDoc = static::GetDocumentFromSelfURL($sPath);
if ($oUploadedDoc) {
return $oUploadedDoc;
}
else
{
// Remote file, let's use the HTTP headers to find the MIME Type
$sData = @file_get_contents($sPath);
if ($sData === false)
{
IssueLog::Error(<<<TXT
// Remote file, let's use the HTTP headers to find the MIME Type
$sData = @file_get_contents($sPath);
if ($sData === false) {
IssueLog::Error(<<<TXT
Failed to load the file from URL. This can happen for multiple reasons:
- Invalid URL
- URL using HTTPS with an untrusted certificate on the remote server
@@ -2514,54 +2500,40 @@ TXT
, LogChannels::CORE, [
'URL' => $sPath,
]);
throw new Exception("Failed to load the file from the URL '$sPath'.");
}
else
{
if (isset($http_response_header))
{
$aHeaders = static::ParseHeaders($http_response_header);
$sMimeType = array_key_exists('Content-Type', $aHeaders) ? strtolower($aHeaders['Content-Type']) : 'application/x-octet-stream';
// Compute the file extension from the MIME Type
foreach ($aKnownExtensions as $sExtValue => $sMime) {
if ($sMime === $sMimeType) {
$sExtension = '.'.$sExtValue;
break;
}
}
}
$sPathName = pathinfo($sPath, PATHINFO_FILENAME);
if (utils::IsNotNullOrEmptyString($sPathName)) {
$sFileName = $sPathName;
}
$sFileName .= $sExtension;
}
$oUploadedDoc = new ormDocument($sData, $sMimeType, $sFileName);
throw new Exception("Failed to load the file from the URL '$sPath'.");
}
}
else if (UserRights::IsAdministrator())
{
// Only administrators are allowed to read local files
$sData = @file_get_contents($sPath);
if ($sData === false)
{
throw new Exception("Failed to load the file '$sPath'. The file does not exist or the current process is not allowed to access it.");
}
$sExtension = strtolower(pathinfo($sPath, PATHINFO_EXTENSION));
$sFileName = basename($sPath);
if (array_key_exists($sExtension, $aKnownExtensions))
{
$sMimeType = $aKnownExtensions[$sExtension];
$sMimeType = 'text/plain'; // Default MIME Type: treat the file as a bunch a characters...
$sFileName = 'uploaded-file'; // Default name for downloaded-files
$sExtension = '.txt'; // Default file extension in case we don't know the MIME Type
if (isset($http_response_header)) {
$aHeaders = static::ParseHeaders($http_response_header);
$sMimeType = array_key_exists('Content-Type', $aHeaders) ? strtolower($aHeaders['Content-Type']) : 'application/x-octet-stream';
// Compute the file extension from the MIME Type
foreach (ormDocument::GetKnownExtensions() as $sExtValue => $sMime) {
if ($sMime === $sMimeType) {
$sExtension = '.'.$sExtValue;
break;
}
}
}
else if (extension_loaded('fileinfo'))
{
$finfo = new finfo(FILEINFO_MIME);
$sMimeType = $finfo->file($sPath);
$sPathName = pathinfo($sPath, PATHINFO_FILENAME);
if (utils::IsNotNullOrEmptyString($sPathName)) {
$sFileName = $sPathName;
}
$oUploadedDoc = new ormDocument($sData, $sMimeType, $sFileName);
$sFileName .= $sExtension;
return new ormDocument($sData, $sMimeType, $sFileName);
}
return $oUploadedDoc;
// Local file
if (UserRights::IsAdministrator()) {
// Only administrators are allowed to read local files
return ormDocument::FromFile($sPath);
}
return null;
}
protected static function ParseHeaders($aHeaders)
@@ -3132,29 +3104,13 @@ TXT
* @throws \Exception
* @since 3.0.0
*/
public static function GetMentionedObjectsFromText(string $sText, string $sFormat = self::ENUM_TEXT_FORMAT_HTML): array
public static function GetMentionedObjectsFromText(string $sText): array
{
// First transform text so it can be parsed
switch ($sFormat) {
case static::ENUM_TEXT_FORMAT_HTML:
$sText = static::HtmlToText($sText);
break;
$aMentionedObjects = [];
$aMentionMatches = [];
$sText = html_entity_decode($sText);
default:
// Don't transform it
break;
}
// Then parse text to find objects
$aMentionedObjects = array();
$aMentionMatches = array();
// Note: As the sanitizer (or CKEditor autocomplete plugin? 🤔) removes data-* attributes from the hyperlink,
// - we can't use the following (simpler) regexp that only checks data attributes on hyperlinks, which would have worked for hyperlinks pointing to any GUIs: '/<a\s*([^>]*)data-object-class="([^"]*)"\s*data-object-id="([^"]*)">/i'
// - instead we use a regexp to match the following pattern '[Some object label](<APP_ROOT_URL>...&class=<OBJECT_CLASS>&id=<OBJECT_ID>...)' which only works for the backoffice
// If we change the sanitizer, we might want to switch to the other regexp as it's universal and easier to read
$sAppRootUrlForRegExp = addcslashes(utils::GetAbsoluteUrlAppRoot(), '/&');
preg_match_all("/\[([^\]]*)\]\({$sAppRootUrlForRegExp}[^\)]*\&class=([^\)\&]*)\&id=([\d]*)[^\)]*\)/i", $sText, $aMentionMatches);
preg_match_all('/<a\s*([^>]*)data-object-class="([^"]*)"\s*data-object-key="([^"]*)"/i', $sText, $aMentionMatches);
foreach ($aMentionMatches[0] as $iMatchIdx => $sCompleteMatch) {
$sMatchedClass = $aMentionMatches[2][$iMatchIdx];

102
composer.lock generated
View File

@@ -3929,6 +3929,82 @@
],
"time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-php81",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php81.git",
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php81\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-php83",
"version": "v1.28.0",
@@ -4976,30 +5052,38 @@
},
{
"name": "twig/twig",
"version": "v3.8.0",
"version": "v3.16.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d"
"reference": "475ad2dc97d65d8631393e721e7e44fb544f0561"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/9d15f0ac07f44dc4217883ec6ae02fd555c6f71d",
"reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/475ad2dc97d65d8631393e721e7e44fb544f0561",
"reference": "475ad2dc97d65d8631393e721e7e44fb544f0561",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"php": ">=8.0.2",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.3",
"symfony/polyfill-php80": "^1.22"
"symfony/polyfill-php81": "^1.29"
},
"require-dev": {
"phpstan/phpstan": "^2.0",
"psr/container": "^1.0|^2.0",
"symfony/phpunit-bridge": "^5.4.9|^6.3|^7.0"
"symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0"
},
"type": "library",
"autoload": {
"files": [
"src/Resources/core.php",
"src/Resources/debug.php",
"src/Resources/escaper.php",
"src/Resources/string_loader.php"
],
"psr-4": {
"Twig\\": "src/"
}
@@ -5032,7 +5116,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.8.0"
"source": "https://github.com/twigphp/Twig/tree/v3.16.0"
},
"funding": [
{
@@ -5044,7 +5128,7 @@
"type": "tidelift"
}
],
"time": "2023-11-21T18:54:41+00:00"
"time": "2024-11-29T08:27:05+00:00"
},
{
"name": "webmozart/assert",

View File

@@ -181,7 +181,7 @@ abstract class Action extends cmdbAbstractObject
{
parent::DisplayBareRelations($oPage, false);
if ($oPage instanceof iTopWebPage) {
if ($oPage instanceof iTopWebPage && !$this->IsNew()) {
$this->GenerateLastExecutionsTab($oPage, $bEditMode);
}
}

View File

@@ -89,7 +89,7 @@ abstract class AsyncTask extends DBObject
// The value is set from null to planned in the setup program
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum('planned,running,idle,error'), "sql"=>"status", "default_value"=>"planned", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("created", array("allowed_values"=>null, "sql"=>"created", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("created", array("allowed_values"=>null, "sql"=>"created", "default_value"=>"NOW()", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("started", array("allowed_values"=>null, "sql"=>"started", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("planned", array("allowed_values"=>null, "sql"=>"planned", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalKey("event_id", array("targetclass"=>"Event", "jointype"=> "", "allowed_values"=>null, "sql"=>"event_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_SILENT, "depends_on"=>array())));
@@ -489,7 +489,7 @@ class AsyncSendNewsroom extends AsyncTask {
MetaModel::Init_AddAttribute(new AttributeInteger("object_id", array("allowed_values"=>null, "sql"=>"object_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("object_class", array("allowed_values"=>null, "sql"=>"object_class", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("url", array("allowed_values"=>null, "sql"=>"url", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>'NOW()', "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
}

View File

@@ -1715,8 +1715,8 @@ class AttributeLinkedSet extends AttributeDefinition
public function GetEditMode()
{
return $this->GetOptional('edit_mode', LINKSET_EDITMODE_ACTIONS);
}
}
/**
* @return int see LINKSET_EDITWHEN_* constants
* @since 3.1.1 3.2.0 N°6385
@@ -1758,7 +1758,7 @@ class AttributeLinkedSet extends AttributeDefinition
{
return $this->GetOptional('with_php_computation', false);
}
public function GetLinkedClass()
{
return $this->Get('linked_class');
@@ -6346,9 +6346,6 @@ class AttributeDateTime extends AttributeDBField
$oFormField = parent::MakeFormField($oObject, $oFormField);
// After call to the parent as it sets the current value
$oFormField->SetCurrentValue($this->GetFormat()->Format($oObject->Get($this->GetCode())));
return $oFormField;
}
@@ -6433,8 +6430,14 @@ class AttributeDateTime extends AttributeDBField
public function GetDefaultValue(DBObject $oHostObject = null)
{
if (!$this->IsNullAllowed()) {
return date($this->GetInternalFormat());
$sDefaultValue = $this->Get('default_value');
if (utils::IsNotNullOrEmptyString($sDefaultValue)) {
try {
$oDate = new DateTimeImmutable($sDefaultValue);
} catch (Exception $e) {
$oDate = new DateTimeImmutable(Expression::FromOQL($sDefaultValue)->Evaluate([]));
}
return $oDate->format($this->GetInternalFormat());
}
return $this->GetNullValue();
}
@@ -9433,8 +9436,13 @@ class AttributeStopWatch extends AttributeDefinition
case 'deadline':
if ($value)
{
$sDate = date(AttributeDateTime::GetInternalFormat(), $value);
$sRet = AttributeDeadline::FormatDeadline($sDate);
if (is_int($value))
{
$sDate = date(AttributeDateTime::GetInternalFormat(), $value);
$sRet = AttributeDeadline::FormatDeadline($sDate);
} else {
$sRet = $value;
}
}
else
{

View File

@@ -70,7 +70,7 @@ class BulkExportResult extends DBObject
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeDateTime("created", array("allowed_values"=>null, "sql"=>"created", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("created", array("allowed_values"=>null, "sql"=>"created", "default_value"=>"NOW()", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("user_id", array("allowed_values"=>null, "sql"=>"user_id", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("chunk_size", array("allowed_values"=>null, "sql"=>"chunk_size", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("format", array("allowed_values"=>null, "sql"=>"format", "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));

View File

@@ -33,7 +33,7 @@ class CMDBChange extends DBObject
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"NOW()", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("allowed_values"=>null, "sql"=>"user_id", "targetclass"=>"User", "is_null_allowed"=>true, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("origin", array("allowed_values"=>new ValueSetEnum(implode(',', [CMDBChangeOrigin::INTERACTIVE, CMDBChangeOrigin::CSV_INTERACTIVE, CMDBChangeOrigin::CSV_IMPORT, CMDBChangeOrigin::WEBSERVICE_SOAP, CMDBChangeOrigin::WEBSERVICE_REST, CMDBChangeOrigin::SYNCHRO_DATA_SOURCE, CMDBChangeOrigin::EMAIL_PROCESSING, CMDBChangeOrigin::CUSTOM_EXTENSION])), "sql"=>"origin", "default_value"=>CMDBChangeOrigin::INTERACTIVE, "is_null_allowed"=>true, "depends_on"=>array())));

View File

@@ -850,6 +850,18 @@
<field id="language" xsi:type="AttributeApplicationLanguage"/>
</fields>
</class>
<class id="Event" _delta="define">
<!-- Generated by toolkit/export-class-to-meta.php -->
<parent>DBObject</parent>
<properties>
<category>core/cmdb,view_in_gui</category>
</properties>
<fields>
<field id="message" xsi:type="AttributeText"/>
<field id="date" xsi:type="AttributeDateTime"/>
<field id="userinfo" xsi:type="AttributeString"/>
</fields>
</class>
<class id="EventNotification" _delta="define">
<!-- Generated by toolkit/export-class-to-meta.php -->
<parent>Event</parent>

View File

@@ -212,6 +212,8 @@ abstract class DBObject implements iDisplay
private $aEventListeners = [];
private array $aAllowedTransitions = [];
private ?string $sStimulusBeingApplied = null;
/**
* DBObject constructor.
*
@@ -1206,7 +1208,7 @@ abstract class DBObject implements iDisplay
if ($aCallInfo["function"] != "ComputeValues") continue;
return; //skip!
}
$this->FireEventComputeValues();
$this->FireEventComputeValues($this->sStimulusBeingApplied);
$oKPI = new ExecutionKPI();
$this->ComputeValues();
$oKPI->ComputeStatsForExtension($this, 'ComputeValues');
@@ -2130,7 +2132,7 @@ abstract class DBObject implements iDisplay
return "Bad type";
}
elseif (($oAtt instanceof AttributeClassAttCodeSet) || ($oAtt instanceof AttributeEnumSet))
elseif ($oAtt instanceof AttributeSet)
{
if (is_string($toCheck))
{
@@ -2669,7 +2671,7 @@ abstract class DBObject implements iDisplay
// Ultimate check - ensure DB integrity
$this->SetReadOnly('No modification allowed during CheckToCreate');
$this->FireEventCheckToWrite();
$this->FireEventCheckToWrite($this->sStimulusBeingApplied);
$this->SetReadWrite();
$oKPI = new ExecutionKPI();
@@ -2865,6 +2867,14 @@ abstract class DBObject implements iDisplay
protected function ListChangedValues(array $aProposal)
{
$aDelta = array();
$sClass = get_class($this);
if (MetaModel::HasLifecycle($sClass) && utils::IsNotNullOrEmptyString($this->sStimulusBeingApplied)) {
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
if (!in_array($sStateAttCode, $aProposal)) {
// Same state but the transition was asked, act as if the state was changed
$aDelta[$sStateAttCode] = $this->m_aCurrValues[$sStateAttCode];
}
}
foreach ($aProposal as $sAtt => $proposedValue)
{
if (!array_key_exists($sAtt, $this->m_aOrigValues))
@@ -3398,7 +3408,7 @@ abstract class DBObject implements iDisplay
$this->OnInsert();
$oKPI->ComputeStatsForExtension($this, 'OnInsert');
$this->FireEventBeforeWrite();
$this->FireEventBeforeWrite(null);
// If not automatically computed, then check that the key is given by the caller
if (!MetaModel::IsAutoIncrementKey($sRootClass)) {
@@ -3533,7 +3543,7 @@ abstract class DBObject implements iDisplay
*/
protected function PostInsertActions(): void
{
$this->FireEventAfterWrite([], true);
$this->FireEventAfterWrite([], true, null);
$oKPI = new ExecutionKPI();
$this->AfterInsert();
$oKPI->ComputeStatsForExtension($this, 'AfterInsert');
@@ -3641,7 +3651,7 @@ abstract class DBObject implements iDisplay
$this->OnUpdate();
$oKPI->ComputeStatsForExtension($this, 'OnUpdate');
$this->FireEventBeforeWrite();
$this->FireEventBeforeWrite($this->sStimulusBeingApplied);
// Freeze the changes at this point
$this->InitPreviousValuesForUpdatedAttributes();
@@ -3809,7 +3819,7 @@ abstract class DBObject implements iDisplay
}
try {
$this->PostUpdateActions($aChanges, $sClass);
$this->PostUpdateActions($this->m_aPreviousValuesForUpdatedAttributes, $sClass);
}
catch (Exception $e) {
$this->LogCRUDExit(__METHOD__, 'Error: '.$e->getMessage());
@@ -3852,7 +3862,7 @@ abstract class DBObject implements iDisplay
*/
protected function PostUpdateActions(array $aChanges): void
{
$this->FireEventAfterWrite($aChanges, false);
$this->FireEventAfterWrite($aChanges, false, $this->sStimulusBeingApplied);
$oKPI = new ExecutionKPI();
$this->AfterUpdate();
$oKPI->ComputeStatsForExtension($this, 'AfterUpdate');
@@ -3864,39 +3874,38 @@ abstract class DBObject implements iDisplay
$this->ActivateOnObjectUpdateTriggersForTargetObjects();
$sClass = get_class($this);
if (MetaModel::HasLifecycle($sClass))
if (utils::IsNotNullOrEmptyString($this->sStimulusBeingApplied))
{
$this->sStimulusBeingApplied = null;
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
if (isset($this->m_aPreviousValuesForUpdatedAttributes[$sStateAttCode])) {
$sPreviousState = $this->m_aPreviousValuesForUpdatedAttributes[$sStateAttCode];
// Change state triggers...
$aParams = array(
'class_list' => MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL),
'previous_state' => $sPreviousState,
'new_state' => $this->Get($sStateAttCode),
);
$oSet = new DBObjectSet(DBObjectSearch::FromOQL('SELECT TriggerOnStateLeave AS t WHERE t.target_class IN (:class_list) AND t.state=:previous_state'), array(), $aParams);
while ($oTrigger = $oSet->Fetch()) {
/** @var \TriggerOnStateLeave $oTrigger */
try {
$oTrigger->DoActivate($this->ToArgs('this'));
}
catch (Exception $e) {
$oTrigger->LogException($e, $this);
utils::EnrichRaisedException($oTrigger, $e);
}
$sPreviousState = $this->m_aPreviousValuesForUpdatedAttributes[$sStateAttCode];
// Change state triggers...
$aParams = array(
'class_list' => MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL),
'previous_state' => $sPreviousState,
'new_state' => $this->Get($sStateAttCode),
);
$oSet = new DBObjectSet(DBObjectSearch::FromOQL('SELECT TriggerOnStateLeave AS t WHERE t.target_class IN (:class_list) AND t.state=:previous_state'), array(), $aParams);
while ($oTrigger = $oSet->Fetch()) {
/** @var \TriggerOnStateLeave $oTrigger */
try {
$oTrigger->DoActivate($this->ToArgs('this'));
}
catch (Exception $e) {
$oTrigger->LogException($e, $this);
utils::EnrichRaisedException($oTrigger, $e);
}
}
$oSet = new DBObjectSet(DBObjectSearch::FromOQL('SELECT TriggerOnStateEnter AS t WHERE t.target_class IN (:class_list) AND t.state=:new_state'), array(), $aParams);
while ($oTrigger = $oSet->Fetch()) {
/** @var \TriggerOnStateEnter $oTrigger */
try {
$oTrigger->DoActivate($this->ToArgs('this'));
}
catch (Exception $e) {
$oTrigger->LogException($e, $this);
utils::EnrichRaisedException($oTrigger, $e);
}
$oSet = new DBObjectSet(DBObjectSearch::FromOQL('SELECT TriggerOnStateEnter AS t WHERE t.target_class IN (:class_list) AND t.state=:new_state'), array(), $aParams);
while ($oTrigger = $oSet->Fetch()) {
/** @var \TriggerOnStateEnter $oTrigger */
try {
$oTrigger->DoActivate($this->ToArgs('this'));
}
catch (Exception $e) {
$oTrigger->LogException($e, $this);
utils::EnrichRaisedException($oTrigger, $e);
}
}
}
@@ -4024,7 +4033,7 @@ abstract class DBObject implements iDisplay
foreach ($aUpdatedLogAttCodes as $sAttCode) {
/** @var \ormCaseLog $oUpdatedCaseLog */
$oUpdatedCaseLog = $this->Get($sAttCode);
$aMentionedObjects = array_merge_recursive($aMentionedObjects, utils::GetMentionedObjectsFromText($oUpdatedCaseLog->GetModifiedEntry()));
$aMentionedObjects = array_merge_recursive($aMentionedObjects, utils::GetMentionedObjectsFromText($oUpdatedCaseLog->GetModifiedEntry(ormCaseLog::ENUM_FORMAT_HTML)));
}
// 3 - Trigger for those objects
@@ -4603,6 +4612,7 @@ abstract class DBObject implements iDisplay
}
if ($bSuccess)
{
$this->sStimulusBeingApplied = $sStimulusCode;
// Stop watches
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{
@@ -6617,7 +6627,7 @@ abstract class DBObject implements iDisplay
* @return void
* @since 3.1.0
*/
protected function FireEventCheckToWrite(): void
protected function FireEventCheckToWrite(?string $sStimulusBeingApplied): void
{
}
@@ -6625,7 +6635,7 @@ abstract class DBObject implements iDisplay
* @return void
* @since 3.1.0
*/
protected function FireEventBeforeWrite()
protected function FireEventBeforeWrite(?string $sStimulusBeingApplied)
{
}
@@ -6635,7 +6645,7 @@ abstract class DBObject implements iDisplay
* @return void
* @since 3.1.0
*/
protected function FireEventAfterWrite(array $aChanges, bool $bIsNew): void
protected function FireEventAfterWrite(array $aChanges, bool $bIsNew, ?string $sStimulusBeingApplied): void
{
}
@@ -6673,7 +6683,7 @@ abstract class DBObject implements iDisplay
* @return void
* @since 3.1.0
*/
protected function FireEventComputeValues(): void
protected function FireEventComputeValues(?string $sStimulusBeingApplied): void
{
}

View File

@@ -51,7 +51,7 @@ class DBProperty extends DBObject
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("value", array("allowed_values"=>null, "sql"=>"value", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("change_date", array("allowed_values"=>null, "sql"=>"change_date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("change_date", array("allowed_values"=>null, "sql"=>"change_date", "default_value"=>"NOW()", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("change_comment", array("allowed_values"=>null, "sql"=>"change_comment", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
}

View File

@@ -39,7 +39,7 @@ class Event extends DBObject implements iDisplay
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"NOW()", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));

View File

@@ -278,7 +278,7 @@ class HTMLDOMSanitizer extends DOMSanitizer
protected static $aTagsWhiteList = array(
'html' => array(),
'body' => array(),
'a' => array('href', 'name', 'style', 'class', 'target', 'title', 'data-role', 'data-object-class', 'data-object-id'),
'a' => array('href', 'name', 'style', 'class', 'target', 'title', 'data-role', 'data-object-class', 'data-object-id', 'data-object-key'),
'p' => array('style', 'class'),
'blockquote' => array('style', 'class'),
'br' => array(),
@@ -354,6 +354,8 @@ class HTMLDOMSanitizer extends DOMSanitizer
'font-style',
'height',
'margin',
'margin-left',
'margin-right',
'padding',
'text-align',
'vertical-align',

View File

@@ -7532,8 +7532,41 @@ abstract class MetaModel
return $aEntries;
}
public static function ResetAllCaches($sEnvironment = null)
{
if (is_null($sEnvironment)) {
$sEnvironment = MetaModel::GetEnvironment();
}
$sEnvironmentId = md5(APPROOT).'-'.$sEnvironment;
$sAppIdentity = 'itop-'.$sEnvironmentId;
require_once(APPROOT.'/core/dict.class.inc.php');
Dict::ResetCache($sAppIdentity);
if (function_exists('apc_delete')) {
foreach (self::GetCacheEntries($sEnvironmentId) as $sKey => $aAPCInfo) {
$sAPCKey = $aAPCInfo['info'];
apc_delete($sAPCKey);
}
}
require_once(APPROOT.'core/userrights.class.inc.php');
UserRights::FlushPrivileges();
// Reset the opcache since otherwise the PHP "model" files may still be cached !!
if (function_exists('opcache_reset')) {
// Zend opcode cache
opcache_reset();
}
require_once(APPROOT.'setup/setuputils.class.inc.php');
SetupUtils::rrmdir(utils::GetCachePath($sEnvironment));
}
/**
* @internal
* @param string $sEnvironmentId
* @deprecated 3.2.1
*/
public static function ResetCache($sEnvironmentId = null)
{
@@ -7557,6 +7590,13 @@ abstract class MetaModel
require_once(APPROOT.'core/userrights.class.inc.php');
UserRights::FlushPrivileges();
// Reset the opcache since otherwise the PHP "model" files may still be cached !!
if (function_exists('opcache_reset'))
{
// Zend opcode cache
opcache_reset();
}
}
/**

View File

@@ -575,6 +575,15 @@ class BinaryExpression extends Expression
case 'LIKE':
$sType = 'like';
break;
case 'NOT LIKE':
$sType = 'notlike';
break;
case 'IN':
$sType = 'in';
break;
case 'NOT IN':
$sType = 'notin';
break;
default:
throw new Exception("Operator '$sOperator' not yet supported");
}
@@ -639,7 +648,26 @@ class BinaryExpression extends Expression
case 'like':
$sEscaped = preg_quote($mRight, '/');
$sEscaped = str_replace(array('%', '_', '\\\\.*', '\\\\.'), array('.*', '.', '%', '_'), $sEscaped);
$result = (int) preg_match("/$sEscaped/i", $mLeft);
$pregRes = preg_match("/$sEscaped/i", $mLeft);
if ($pregRes === false) {
throw new Exception("Error in regular expression '$sEscaped'");
}
$result = ($pregRes === 1);
break;
case 'notlike':
$sEscaped = preg_quote($mRight, '/');
$sEscaped = str_replace(array('%', '_', '\\\\.*', '\\\\.'), array('.*', '.', '%', '_'), $sEscaped);
$pregRes = preg_match("/$sEscaped/i", $mLeft);
if ($pregRes === false) {
throw new Exception("Error in regular expression '$sEscaped'");
}
$result = ($pregRes !== 1);
break;
case 'in':
$result = in_array($mLeft, $mRight);
break;
case 'notin':
$result = !in_array($mLeft, $mRight);
break;
}
return $result;
@@ -2250,7 +2278,12 @@ class ListExpression extends Expression
*/
public function Evaluate(array $aArgs)
{
throw new Exception('list expression not yet supported');
//throw new Exception('list expression not yet supported');
$aResult = [];
foreach ($this->m_aExpressions as $oExpressions) {
$aResult[] = $oExpressions->Evaluate($aArgs);
}
return $aResult;
}
/**

View File

@@ -36,7 +36,13 @@ class UnknownClassOqlException extends OqlNormalizeException
{
public function __construct($sInput, OqlName $oName, $aExpecting = null)
{
parent::__construct('Unknown class', $sInput, $oName, $aExpecting);
$aAllowedClasses = [];
foreach ($aExpecting as $sClass) {
if (UserRights::IsActionAllowed($sClass, UR_ACTION_READ)) {
$aAllowedClasses[] = $sClass;
}
}
parent::__construct('Unknown class', $sInput, $oName, $aAllowedClasses);
}
public function GetUserFriendlyDescription()

View File

@@ -48,6 +48,42 @@ class ormDocument
* @since 3.1.0
*/
public const DEFAULT_DOWNLOADS_COUNT = 0;
private static $aKnownExtensions = [
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'gif' => 'image/gif',
'png' => 'image/png',
'pdf' => 'application/pdf',
'doc' => 'application/msword',
'dot' => 'application/msword',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',
'vsd' => 'application/x-visio',
'vdx' => 'application/visio.drawing',
'odt' => 'application/vnd.oasis.opendocument.text',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
'odp' => 'application/vnd.oasis.opendocument.presentation',
'zip' => 'application/zip',
'txt' => 'text/plain',
'htm' => 'text/html',
'html' => 'text/html',
'exe' => 'application/octet-stream',
];
public static function GetKnownExtensions(): array
{
return self::$aKnownExtensions;
}
protected $m_data;
protected $m_sMimeType;
@@ -76,6 +112,36 @@ class ormDocument
$this->m_iDownloadsCount = $iDownloadsCount;
}
/**
* @param string $sPath Absolute path of the document to read
*
* @return \ormDocument
* @throws \Exception
*/
public static function FromFile(string $sPath): ormDocument
{
$sPath = utils::RealPath($sPath, APPROOT);
if (false === $sPath) {
throw new Exception("Failed to load the file '$sPath'. The file does not exist or the current process is not allowed to access it.");
}
$sData = @file_get_contents($sPath);
if (false === $sData) {
throw new Exception("Failed to load the file '$sPath'. The file does not exist or the current process is not allowed to access it.");
}
$sExtension = strtolower(pathinfo($sPath, PATHINFO_EXTENSION));
$sFileName = basename($sPath);
$sMimeType = 'text/plain';
if (array_key_exists($sExtension, ormDocument::$aKnownExtensions)) {
$sMimeType = ormDocument::$aKnownExtensions[$sExtension];
} else if (extension_loaded('fileinfo')) {
$fInfo = new finfo(FILEINFO_MIME);
$sMimeType = $fInfo->file($sPath);
}
return new ormDocument($sData, $sMimeType, $sFileName);
}
public function __toString()
{
if($this->IsEmpty()) return '';

View File

@@ -42,8 +42,8 @@ class iTopOwnershipToken extends DBObject
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeDateTime("acquired", array("allowed_values"=>null, "sql"=>'acquired', "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("last_seen", array("allowed_values"=>null, "sql"=>'last_seen', "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("acquired", array("allowed_values"=>null, "sql"=>'acquired', "default_value"=>'NOW()', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("last_seen", array("allowed_values"=>null, "sql"=>'last_seen', "default_value"=>'NOW()', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("obj_class", array("allowed_values"=>null, "sql"=>'obj_class', "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("obj_key", array("allowed_values"=>null, "sql"=>'obj_key', "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("token", array("allowed_values"=>null, "sql"=>'token', "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));

View File

@@ -1921,50 +1921,45 @@ class UserRights
*/
protected static function FindUser($sLogin, $sAuthentication = 'any', $bAllowDisabledUsers = false)
{
if ($sAuthentication == 'any')
{
$oUser = self::FindUser($sLogin, 'internal');
if ($oUser == null)
{
$oUser = self::FindUser($sLogin, 'external');
if ($sAuthentication === 'any') {
$oUser = self::FindUser($sLogin, 'internal', $bAllowDisabledUsers);
if ($oUser !== null) {
return $oUser;
}
return self::FindUser($sLogin, 'external', $bAllowDisabledUsers);
}
else
{
if (!isset(self::$m_aCacheUsers))
{
self::$m_aCacheUsers = array('internal' => array(), 'external' => array());
}
if (!isset(self::$m_aCacheUsers[$sAuthentication][$sLogin]))
{
switch($sAuthentication)
{
case 'external':
$sBaseClass = 'UserExternal';
break;
case 'internal':
$sBaseClass = 'UserInternal';
break;
default:
echo "<p>sAuthentication = $sAuthentication</p>\n";
assert(false); // should never happen
}
$oSearch = DBObjectSearch::FromOQL("SELECT $sBaseClass WHERE login = :login");
$oSearch->AllowAllData();
if (!$bAllowDisabledUsers)
{
$oSearch->AddCondition('status', 'enabled');
}
$oSet = new DBObjectSet($oSearch, array(), array('login' => $sLogin));
$oUser = $oSet->fetch();
self::$m_aCacheUsers[$sAuthentication][$sLogin] = $oUser;
}
$oUser = self::$m_aCacheUsers[$sAuthentication][$sLogin];
if (!isset(self::$m_aCacheUsers)) {
self::$m_aCacheUsers = [ 'internal' => [], 'external' => [] ];
}
return $oUser;
if (! isset(self::$m_aCacheUsers[$sAuthentication]) || ! array_key_exists($sLogin, self::$m_aCacheUsers[$sAuthentication])) {
switch($sAuthentication) {
case 'external':
$sBaseClass = 'UserExternal';
break;
case 'internal':
$sBaseClass = 'UserInternal';
break;
default:
echo "<p>sAuthentication = $sAuthentication</p>\n";
assert(false); // should never happen
}
$oSearch = DBObjectSearch::FromOQL("SELECT $sBaseClass WHERE login = :login");
$oSearch->AllowAllData();
if (!$bAllowDisabledUsers) {
$oSearch->AddCondition('status', 'enabled');
}
$oSet = new DBObjectSet($oSearch, array(), array('login' => $sLogin));
$oUser = $oSet->fetch();
self::$m_aCacheUsers[$sAuthentication][$sLogin] = $oUser;
}
return self::$m_aCacheUsers[$sAuthentication][$sLogin];
}
/**

View File

@@ -1,4 +1,4 @@
/*!
/*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,4 +1,4 @@
/*!
/*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,4 +1,4 @@
/*!
/*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,4 +1,4 @@
/*!
/*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,4 +1,4 @@
/*!
/*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,4 +1,4 @@
/*!
/*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,4 +1,4 @@
/*!
/*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,4 +1,4 @@
/*!
/*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,4 +1,4 @@
/*!
/*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,4 +1,4 @@
/*!
/*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,4 +1,4 @@
/*!
/*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -4,11 +4,8 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
*
*/
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'CAS:Error:UserNotAllowed' => '用户被禁止登录',
'CAS:Login:SignIn' => '使用CAS登录',

View File

@@ -160,8 +160,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
private static function InitCASClient()
{
$bCASDebug = Config::Get('cas_debug');
if ($bCASDebug)
{
if ($bCASDebug) {
phpCAS::setLogger(new CASLogger(APPROOT.'log/cas.log'));
}
@@ -171,18 +170,17 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
$iCASPort = Config::Get('cas_port');
$sCASContext = Config::Get('cas_context');
$sServiceBaseURL = Config::Get('service_base_url', self::GetServiceBaseURL());
phpCAS::client($sCASVersion, $sCASHost, $iCASPort, $sCASContext, $sServiceBaseURL, false /* session already started */);
if (!phpCAS::isInitialized()) {
phpCAS::client($sCASVersion, $sCASHost, $iCASPort, $sCASContext, $sServiceBaseURL, false /* session already started */);
}
$sCASCACertPath = Config::Get('cas_server_ca_cert_path');
if (empty($sCASCACertPath))
{
if (empty($sCASCACertPath)) {
// If no certificate authority is provided, do not attempt to validate
// the server's certificate
// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
phpCAS::setNoCasServerValidation();
}
else
{
} else {
phpCAS::setCasServerCACert($sCASCACertPath);
}
}

View File

@@ -4,12 +4,39 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*
*/
/**
* @author Robert Deng <denglx@gmail.com>
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: UserExternal
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:UserExternal' => '外部用户',
'Class:UserExternal+' => '用户在'.ITOP_APPLICATION_SHORT.'外部验证身份',

View File

@@ -4,12 +4,38 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
* @author Robert Deng <denglx@gmail.com>
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: UserLDAP
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:UserLDAP' => 'LDAP用户',
'Class:UserLDAP+' => '用户身份由LDAP认证',

View File

@@ -4,15 +4,44 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
* @author Robert Deng <denglx@gmail.com>
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: UserLocal
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:UserLocal' => ITOP_APPLICATION_SHORT.' 用户',
'Class:UserLocal+' => '用户由'.ITOP_APPLICATION_SHORT.'验证身份',
'Class:UserLocal/Attribute:password' => '密码',
'Class:UserLocal/Attribute:password+' => '用于验证用户身份的字符串',
'Class:UserLocal/Attribute:expiration' => '密码过期',
'Class:UserLocal/Attribute:expiration+' => '密码过期状态 (需要一个扩展才能生效)',
'Class:UserLocal/Attribute:expiration/Value:can_expire' => '允许过期',
@@ -23,11 +52,10 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:UserLocal/Attribute:expiration/Value:never_expire+' => '',
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => '一次性密码',
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => '用户不允许修改密码.',
'Class:UserLocal/Attribute:password' => '密码',
'Class:UserLocal/Attribute:password+' => '用于验证用户身份的字符串',
'Class:UserLocal/Attribute:password_renewed_date' => '密码更新',
'Class:UserLocal/Attribute:password_renewed_date+' => '上次修改密码的时间',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => '不允许用户为自己设置 "一次性密码" 的失效期限',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => '密码必须至少8个字符, 包含大小写, 数字和特殊字符.',
'UserLocal:password:expiration' => '下面的区域需要插件扩展',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => '不允许用户为自己设置 "一次性密码" 的失效期限',
]);

View File

@@ -4,11 +4,23 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'theme:darkmoon' => '暗月',
]);

View File

@@ -170,7 +170,7 @@ class DatabaseAnalyzer
$this->CheckHK($sClass, $sAttCode, $aErrorsAndFixes);
}
}
elseif ($oAttDef->IsDirectField() && !($oAttDef instanceof AttributeTagSet))
elseif ($oAttDef->IsDirectField() && !($oAttDef instanceof AttributeSet))
{
$this->CheckAllowedValues($sClass, $sAttCode, $oAttDef, $sTable, $sKeyField, $aErrorsAndFixes);
}

View File

@@ -4,63 +4,93 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'DBAnalyzer-Fetch-Count-Error' => '读取计数出错于 `%1$s`, %2$d个记录已读取 / %3$d已',
'DBAnalyzer-Integrity-FinalClass' => '字段 `%2$s`.`%1$s` 必须是相同的值, 而不是 `%3$s`.`%1$s`',
'DBAnalyzer-Integrity-HKInvalid' => '损坏的层级链 `%1$s`',
'DBAnalyzer-Integrity-InvalidExtKey' => '无效的外键%1$s (列: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-InvalidValue' => '无效的值%1$s (列: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-MissingExtKey' => '外键丢失%1$s (列: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-OrphanRecord' => '孤立记录位于 `%1$s`, 其应该有副本位于表 `%2$s`',
'DBAnalyzer-Integrity-RootFinalClass' => '字段 `%2$s`.`%1$s` 必须包含一个有效的类型',
'DBAnalyzer-Integrity-UsersWithoutProfile' => '一些用户账号没有角色',
'DBTools:Analyze' => '分析',
'DBTools:Base' => '数据库',
// Database inconsistencies
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
// Dictionary entries go here
'Menu:DBToolsMenu' => '数据库工具',
'DBTools:Class' => '类型',
'DBTools:Count' => '数',
'DBTools:DatabaseInfo' => '数据库信息',
'DBTools:DetailedErrorLimit' => '列表限制为%1$s错误',
'DBTools:DetailedErrorTitle' => '%2$s个错误在类型%1$s: %3$s',
'DBTools:Details' => '显示详情',
'DBTools:Title' => '数据库维护工具',
'DBTools:ErrorsFound' => '发现错误',
'DBTools:Indication' => '重要: 修复数据库错误后, 可能会出现新的不一致, 您必须重新运行一次分析.',
'DBTools:Disclaimer' => '免责申明: 在应用修复之前, 应先备份数据库',
'DBTools:Error' => '错误',
'DBTools:ErrorsFound' => '发现错误',
'DBTools:FetchCheck' => '提取检查 (耗时长)',
'DBTools:FixitSQLquery' => '修复问题的SQL查询 (指示)',
'DBTools:HideIds' => '错误列表',
'DBTools:Inconsistencies' => '数据库不一致',
'DBTools:Indication' => '重要: 修复数据库错误后, 可能会出现新的不一致, 您必须重新运行一次分析.',
'DBTools:IntegrityCheck' => '完整性检查',
'DBTools:LostAttachments' => '附件缺失',
'DBTools:LostAttachments:Button:Analyze' => '分析',
'DBTools:LostAttachments:Button:Busy' => '请稍后...',
'DBTools:LostAttachments:Button:Restore' => '还原',
'DBTools:LostAttachments:Button:Restore:Confirm' => '此操作无法回退, 请确认是否继续还原.',
'DBTools:LostAttachments:Disclaimer' => '可以在此搜索数据库中丢失或错放的附件. 这不是数据恢复工具, 其无法恢复已删除的数据.',
'DBTools:LostAttachments:History' => '附件 "%1$s" 已使用数据库工具还原',
'DBTools:LostAttachments:Step:Analyze' => '首先, 通过分析数据库来搜索丢失或误挪动的附件.',
'DBTools:LostAttachments:Step:AnalyzeResults' => '分析结果:',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => '当前位置',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => '文件名',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => '移动到...',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => '非常好! 所有附件都是正常的.',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => '某些附件 (%1$d) 看起来放错了位置. 请检查下面的列表并选择要挪动的文件.',
'DBTools:LostAttachments:Step:RestoreResults' => '还原结果:',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d的附件被还原.',
'DBTools:LostAttachments:StoredAsInlineImage' => '存储为内嵌图像',
'DBTools:NoError' => '数据库正确',
'DBTools:Count' => '个数',
'DBTools:SQLquery' => 'SQL查询',
'DBTools:FixitSQLquery' => '修复问题的SQL查询 (指示)',
'DBTools:SQLresult' => 'SQL结果',
'DBTools:SelectAnalysisType' => '请选择分析类型',
'DBTools:ShowAll' => '显示所有错误',
'DBTools:NoError' => '数据库正确',
'DBTools:HideIds' => '错误列表',
'DBTools:ShowIds' => '详细视图',
'DBTools:ShowReport' => '报告',
'DBTools:IntegrityCheck' => '完整性检查',
'DBTools:FetchCheck' => '提取检查 (耗时长)',
'DBTools:SelectAnalysisType' => '请选择分析类型',
'DBTools:Analyze' => '分析',
'DBTools:Details' => '显示详情',
'DBTools:ShowAll' => '显示所有错误',
'DBTools:Inconsistencies' => '数据库不一致',
'DBTools:DetailedErrorTitle' => '%2$s个错误在类型%1$s: %3$s',
'DBTools:DetailedErrorLimit' => '列表限制为%1$s错误',
'DBAnalyzer-Integrity-OrphanRecord' => '孤立记录位于 `%1$s`, 其应该有副本位于表 `%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' => '一些用户账号没有角色',
'DBAnalyzer-Integrity-HKInvalid' => '损坏的层级链 `%1$s`',
'DBAnalyzer-Fetch-Count-Error' => '读取计数出错于 `%1$s`, %2$d个记录已读取 / %3$d已',
'DBAnalyzer-Integrity-FinalClass' => '字段 `%2$s`.`%1$s` 必须是相同的值, 而不是 `%3$s`.`%1$s`',
'DBAnalyzer-Integrity-RootFinalClass' => '字段 `%2$s`.`%1$s` 必须包含一个有效的类型',
));
// Database Info
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'DBTools:DatabaseInfo' => '数据库信息',
'DBTools:Base' => '数据库',
'DBTools:Size' => '大小',
'DBTools:Title' => '数据库维护工具',
'Menu:DBToolsMenu' => '数据库工具',
]);
));
// Lost attachments
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'DBTools:LostAttachments' => '附件缺失',
'DBTools:LostAttachments:Disclaimer' => '可以在此搜索数据库中丢失或错放的附件. 这不是数据恢复工具, 其无法恢复已删除的数据.',
'DBTools:LostAttachments:Button:Analyze' => '分析',
'DBTools:LostAttachments:Button:Restore' => '还原',
'DBTools:LostAttachments:Button:Restore:Confirm' => '此操作无法回退, 请确认是否继续还原.',
'DBTools:LostAttachments:Button:Busy' => '请稍候...',
'DBTools:LostAttachments:Step:Analyze' => '首先, 通过分析数据库来搜索丢失或误挪动的附件.',
'DBTools:LostAttachments:Step:AnalyzeResults' => '分析结果:',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => '非常好! 所有附件都是正常的.',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => '某些附件 (%1$d) 看起来放错了位置. 请检查下面的列表并选择要挪动的文件.',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => '文件名',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => '当前位置',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => '移动到...',
'DBTools:LostAttachments:Step:RestoreResults' => '还原结果:',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d的附件被还原.',
'DBTools:LostAttachments:StoredAsInlineImage' => '存储为内嵌图像',
'DBTools:LostAttachments:History' => '附件 "%1$s" 已使用数据库工具还原',
));

View File

@@ -4,57 +4,83 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*
*/
/**
*
*/
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Attachments:TabTitle_Count' => '附件 (%1$d)',
'Attachments:EmptyTabTitle' => '附件',
'Attachments:FieldsetTitle' => '附件',
'Attachments:DeleteBtn' => '删除',
'Attachments:History_File_Added' => '附件%1$s已添加.',
'Attachments:History_File_Removed' => '附件%1$s已移除.',
'Attachments:AddAttachment' => '添加附件: ',
'Attachments:UploadNotAllowedOnThisSystem' => '本系统不支持文件上传.',
'Attachment:Max_Go' => '(最大文件尺寸: %1$s GB)',
'Attachment:Max_Ko' => '(最大文件尺寸: %1$s KB)',
'Attachment:Max_Mo' => '(最大文件尺寸: %1$s MB)',
'Attachments:AddAttachment' => '添加附件: ',
'Attachments:DeleteBtn' => '删除',
'Attachments:EmptyTabTitle' => '附件',
'Attachments:Error:FileTooLarge' => '上传的文件过大. %1$s',
'Attachments:Error:UploadedFileEmpty' => '收到的文件为空, 无法添加. 可能是因为您发送的是空文件,或者咨询'.ITOP_APPLICATION_SHORT.'管理员服务器磁盘是否已满.',
'Attachments:FieldsetTitle' => '附件',
'Attachments:File:Date' => '上传日期',
'Attachments:File:DownloadsCount' => '下载',
'Attachments:File:MimeType' => '类型',
'Attachments:File:Name' => '文件名',
'Attachments:File:Size' => '大小',
'Attachments:File:Thumbnail' => '图标',
'Attachments:File:Uploader' => '上传者',
'Attachments:History_File_Added' => '附件%1$s已添加.',
'Attachments:History_File_Removed' => '附件%1$s已移除.',
'Attachments:NoAttachment' => '没有附件. ',
'Attachments:PreviewNotAvailable' => '此附件类型不支持预览.',
'Attachments:Error:FileTooLarge' => '上传的文件过大. %1$s',
'Attachments:Error:UploadedFileEmpty' => '收到的文件为空, 无法添加.
可能是因为您发送的是空文件,
或者咨询 '.ITOP_APPLICATION_SHORT.' 管理员,检查 '.ITOP_APPLICATION_SHORT.' 服务器硬盘是否满了.',
'Attachments:Render:Icons' => '显示为图标',
'Attachments:Render:Table' => '显示为列表',
'Attachments:TabTitle_Count' => '附件 (%1$d)',
'Attachments:UploadNotAllowedOnThisSystem' => '本系统不支持文件上传.',
'Class:Attachment' => '附件',
'Class:Attachment+' => '',
'Class:Attachment/Attribute:contact_id' => '联系人编号',
'Class:Attachment/Attribute:contact_id+' => '~~',
'Class:Attachment/Attribute:contents' => '内容',
'Class:Attachment/Attribute:contents+' => '',
'Class:Attachment/Attribute:creation_date' => '创建日期',
'Class:Attachment/Attribute:creation_date+' => '~~',
'Class:Attachment/Attribute:expire' => '过期',
'Class:Attachment/Attribute:expire+' => '~~',
'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' => '项目组织',
'Class:Attachment/Attribute:item_org_id+' => '',
'Class:Attachment/Attribute:temp_id' => '临时编号',
'Class:Attachment/Attribute:temp_id+' => '~~',
'Class:Attachment/Attribute:user_id' => '用户编号',
'Class:Attachment/Attribute:user_id+' => '~~',
'Class:TriggerOnAttachmentDownload' => '触发器 (于对象附件下载时)',
'Class:TriggerOnAttachmentDownload+' => '触发器于指定类型 [子类型] 对象附件下载时',
'UI:Attachments:DropYourFileHint' => '将文件拖放到此区域的任意位置',
]);
//
// Class: Attachment
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:Attachment' => '附件',
'Class:Attachment+' => '',
'Class:Attachment/Attribute:expire' => '过期',
'Class:Attachment/Attribute:expire+' => '',
'Class:Attachment/Attribute:temp_id' => '临时编号',
'Class:Attachment/Attribute:temp_id+' => '',
'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' => '项目组织',
'Class:Attachment/Attribute:item_org_id+' => '',
'Class:Attachment/Attribute:contents' => '内容',
'Class:Attachment/Attribute:contents+' => '',
]);
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Attachments:File:Thumbnail' => '图标',
'Attachments:File:Name' => '文件名',
'Attachments:File:Date' => '上传日期',
'Attachments:File:Uploader' => '上传者',
'Attachments:File:Size' => '大小',
'Attachments:File:MimeType' => '类型',
'Attachments:File:DownloadsCount' => '下载',
]);
//
// Class: Attachment
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:Attachment/Attribute:creation_date' => '创建日期',
'Class:Attachment/Attribute:creation_date+' => '~~',
'Class:Attachment/Attribute:user_id' => '用户编号',
'Class:Attachment/Attribute:user_id+' => '~~',
'Class:Attachment/Attribute:contact_id' => '联系人编号',
'Class:Attachment/Attribute:contact_id+' => '~~',
]);
//
// Class: TriggerOnAttachmentDownload
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:TriggerOnAttachmentDownload' => '触发器 (于对象附件下载时)',
'Class:TriggerOnAttachmentDownload+' => '触发器于指定类型 [子类型] 对象附件下载时',
]);

View File

@@ -4,44 +4,58 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Menu:BackupStatus' => '定时备份',
'bkp-backup-running' => '备份正在进行, 请稍...',
'bkp-button-backup-now' => '立即备份!',
'bkp-button-restore-now' => '还原!',
'bkp-confirm-backup' => '请确认是否立即开始备份.',
'bkp-confirm-restore' => '请确认要还原的备份文件是 %1$s.',
'bkp-dir-not-writeable' => '%1$s没有写入权限',
'bkp-free-disk-space' => '<b>%1$s可用空间</b>位于<code>%2$s</code>',
'bkp-missing-dir' => '目标目录<code>%1$s</code>找不到',
'bkp-mysqldump-issue' => 'mysqldump无法运行 (retcode=%1$d): 请确认它安装在正确的路径, 或者调整'.ITOP_APPLICATION_SHORT.'配置文件的参数mysql_bindir',
'bkp-mysqldump-notfound' => 'mysqldump找不到: %1$s - 请确认它安装在正确的路径, 或者调整'.ITOP_APPLICATION_SHORT.'配置文件的参数mysql_bindir.',
'bkp-mysqldump-ok' => '已找到mysqldump : %1$s',
'bkp-name-sample' => '备份文件将以数据库名, 日期和时间进行命名. 例如: %1$s',
'bkp-next-backup' => '下一次备份将发生在<b>%1$s</b> (%2$s) 的%3$s',
'bkp-next-backup-unknown' => '下一次备份<b>尚未被计划</b>.',
'bkp-next-to-delete' => '当下一次备份时将被删除 (参阅设置 "retention_count")',
'bkp-backup-running' => '备份正在进行, 请稍...',
'bkp-restore-running' => '还原正在进行, 请稍等...',
'bkp-retention' => '最多<b>%1$d份备份文件</b>在目标目录.',
'bkp-status-backups-auto' => '定时备份',
'bkp-status-backups-manual' => '手动备份',
'bkp-status-backups-none' => '尚未开始备份',
'bkp-status-checks' => '设置与检查',
'Menu:BackupStatus' => '定时备份',
'bkp-status-title' => '定时备份',
'bkp-success-restore' => '还原成功.',
'bkp-table-actions' => '操作',
'bkp-table-actions+' => '',
'bkp-status-checks' => '设置与检查',
'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-dir-not-writeable' => '%1$s没有写入权限',
'bkp-wrong-format-spec' => '当前文件名格式错误 (%1$s). 默认格式应该是: %2$s',
'bkp-name-sample' => '备份文件将以数据库名, 日期和时间进行命名. 例如: %1$s',
'bkp-week-days' => '在每个<b>%1$s的%2$s</b>进行备份',
'bkp-retention' => '最多<b>%1$d份备份文件</b>在目标目录.',
'bkp-next-to-delete' => '当下一次备份时将被删除 (参阅设置 "retention_count")',
'bkp-table-file' => '文件',
'bkp-table-file+' => '只有扩展名是.zip的文件才被认为是备份文件',
'bkp-table-size' => '大小',
'bkp-table-size+' => '',
'bkp-table-actions' => '操作',
'bkp-table-actions+' => '',
'bkp-status-backups-auto' => '定时备份',
'bkp-status-backups-manual' => '手动备份',
'bkp-status-backups-none' => '尚未开始备份',
'bkp-next-backup' => '下一次备份将发生在<b>%1$s</b> (%2$s) 的%3$s',
'bkp-next-backup-unknown' => '下一次备份<b>尚未被计划</b>.',
'bkp-button-backup-now' => '立即备份!',
'bkp-button-restore-now' => '还原!',
'bkp-confirm-backup' => '请确认是否立即开始备份.',
'bkp-confirm-restore' => '请确认要还原的备份文件是 %1$s.',
'bkp-wait-backup' => '请等待备份完成...',
'bkp-wait-restore' => '请等待还原完成...',
'bkp-week-days' => '在每个<b>%1$s的%2$s</b>进行备份',
'bkp-wrong-format-spec' => '当前文件名格式错误 (%1$s). 默认格式应该是: %2$s',
'bkp-success-restore' => '还原成功.',
]);

View File

@@ -1,44 +1,86 @@
<?php
// Copyright (C) 2010-2024 Combodo SAS
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
* @author Benjamin Planque <benjamin.planque@combodo.com>
*
*/
*/
//////////////////////////////////////////////////////////////////////
// Note: The classes have been grouped by categories: bizmodel
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Classes in 'bizmodel'
//////////////////////////////////////////////////////////////////////
//
//
// Class: lnkFunctionalCIToProviderContract
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:lnkFunctionalCIToProviderContract' => '关联功能配置项/供应商合同',
'Class:lnkFunctionalCIToProviderContract+' => '',
'Class:lnkFunctionalCIToProviderContract/Name' => '%1$s / %2$s',
'Class:lnkFunctionalCIToProviderContract/Attribute:providercontract_id' => '供应商合同',
'Class:lnkFunctionalCIToProviderContract/Attribute:providercontract_id+' => '',
'Class:lnkFunctionalCIToProviderContract/Attribute:providercontract_name' => '供应商合同名称',
'Class:lnkFunctionalCIToProviderContract/Attribute:providercontract_name+' => '',
'Class:lnkFunctionalCIToProviderContract/Attribute:functionalci_id' => '配置项',
'Class:lnkFunctionalCIToProviderContract/Attribute:functionalci_id+' => '',
'Class:lnkFunctionalCIToProviderContract/Attribute:functionalci_name' => '配置项名称',
'Class:lnkFunctionalCIToProviderContract/Attribute:functionalci_name+' => '',
]);
//
// Class: lnkFunctionalCIToService
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:lnkFunctionalCIToService' => '关联 功能配置项/服务',
'Class:lnkFunctionalCIToService+' => '',
'Class:lnkFunctionalCIToService/Name' => '%1$s / %2$s~~',
'Class:lnkFunctionalCIToService/Attribute:service_id' => '服务',
'Class:lnkFunctionalCIToService/Attribute:service_id+' => '',
'Class:lnkFunctionalCIToService/Attribute:service_name' => '服务名称',
'Class:lnkFunctionalCIToService/Attribute:service_name+' => '',
'Class:lnkFunctionalCIToService/Attribute:functionalci_id' => '配置项',
'Class:lnkFunctionalCIToService/Attribute:functionalci_id+' => '',
'Class:lnkFunctionalCIToService/Attribute:functionalci_name' => '配置项名称',
'Class:lnkFunctionalCIToService/Attribute:functionalci_name+' => '',
]);
//
// Class: FunctionalCI
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:FunctionalCI/Attribute:providercontracts_list' => '供应商合同',
'Class:FunctionalCI/Attribute:providercontracts_list+' => '此配置项的所有供应商合同',
'Class:FunctionalCI/Attribute:services_list' => '服务',
'Class:FunctionalCI/Attribute:services_list+' => '此配置项影响的所有服务',
]);
//
// Class: Document
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:Document/Attribute:contracts_list' => '合同',
'Class:Document/Attribute:contracts_list+' => '此文档关联的所有合同',
'Class:Document/Attribute:services_list' => '服务',
'Class:Document/Attribute:services_list+' => '此文档关联的所有服务',
'Class:FunctionalCI/Attribute:providercontracts_list' => '供应商合同',
'Class:FunctionalCI/Attribute:providercontracts_list+' => '此配置项的所有供应商合同',
'Class:FunctionalCI/Attribute:services_list' => '服务',
'Class:FunctionalCI/Attribute:services_list+' => '此配置项影响的所有服务',
'Class:lnkFunctionalCIToProviderContract' => '关联功能配置项/供应商合同',
'Class:lnkFunctionalCIToProviderContract+' => '',
'Class:lnkFunctionalCIToProviderContract/Attribute:functionalci_id' => '配置项',
'Class:lnkFunctionalCIToProviderContract/Attribute:functionalci_id+' => '',
'Class:lnkFunctionalCIToProviderContract/Attribute:functionalci_name' => '配置项名称',
'Class:lnkFunctionalCIToProviderContract/Attribute:functionalci_name+' => '',
'Class:lnkFunctionalCIToProviderContract/Attribute:providercontract_id' => '供应商合同',
'Class:lnkFunctionalCIToProviderContract/Attribute:providercontract_id+' => '',
'Class:lnkFunctionalCIToProviderContract/Attribute:providercontract_name' => '供应商合同名称',
'Class:lnkFunctionalCIToProviderContract/Attribute:providercontract_name+' => '',
'Class:lnkFunctionalCIToProviderContract/Name' => '%1$s / %2$s~~',
'Class:lnkFunctionalCIToService' => '关联功能配置项/服务',
'Class:lnkFunctionalCIToService+' => '',
'Class:lnkFunctionalCIToService/Attribute:functionalci_id' => '配置项',
'Class:lnkFunctionalCIToService/Attribute:functionalci_id+' => '',
'Class:lnkFunctionalCIToService/Attribute:functionalci_name' => '配置项名称',
'Class:lnkFunctionalCIToService/Attribute:functionalci_name+' => '',
'Class:lnkFunctionalCIToService/Attribute:service_id' => '服务',
'Class:lnkFunctionalCIToService/Attribute:service_id+' => '',
'Class:lnkFunctionalCIToService/Attribute:service_name' => '服务名称',
'Class:lnkFunctionalCIToService/Attribute:service_name+' => '',
'Class:lnkFunctionalCIToService/Name' => '%1$s / %2$s~~',
]);

View File

@@ -1,20 +1,48 @@
<?php
// Copyright (C) 2010-2024 Combodo SAS
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
* @author Benjamin Planque <benjamin.planque@combodo.com>
*
*/
//////////////////////////////////////////////////////////////////////
// Note: The classes have been grouped by categories: bizmodel
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Classes in 'bizmodel'
//////////////////////////////////////////////////////////////////////
//
//
// Class: lnkFunctionalCIToTicket
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:FunctionalCI/Attribute:tickets_list' => '工单',
'Class:FunctionalCI/Attribute:tickets_list+' => '此配置项包含的所有工单',
'Class:lnkFunctionalCIToTicket' => '关联功能配置项/工单',
'Class:lnkFunctionalCIToTicket' => '关联 功能配置项/工单',
'Class:lnkFunctionalCIToTicket+' => '',
'Class:lnkFunctionalCIToTicket/Name' => '%1$s / %2$s',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_id' => '工单',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_id+' => '',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_ref' => '工单编号',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_ref+' => '',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_title' => '工单标题',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_title+' => '~~',
'Class:lnkFunctionalCIToTicket/Attribute:functionalci_id' => '配置项',
'Class:lnkFunctionalCIToTicket/Attribute:functionalci_id+' => '',
'Class:lnkFunctionalCIToTicket/Attribute:functionalci_name' => '配置项名称',
@@ -22,14 +50,15 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:lnkFunctionalCIToTicket/Attribute:impact' => '影响 (文本)',
'Class:lnkFunctionalCIToTicket/Attribute:impact+' => '',
'Class:lnkFunctionalCIToTicket/Attribute:impact_code' => '影响',
'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:computed' => '自动添加',
'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:manual' => '手动添加',
'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:computed' => '自动添加',
'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:not_impacted' => '不通知',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_id' => '工单',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_id+' => '',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_ref' => '工单编号',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_ref+' => '',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_title' => '工单标题',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_title+' => '~~',
'Class:lnkFunctionalCIToTicket/Name' => '%1$s / %2$s~~',
]);
//
// Class: FunctionalCI
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:FunctionalCI/Attribute:tickets_list' => '工单',
'Class:FunctionalCI/Attribute:tickets_list+' => '此配置项包含的所有工单',
]);

View File

@@ -4,233 +4,291 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Menu:ChangeManagement' => '变更管理',
'Menu:Change:Overview' => '概况',
'Menu:Change:Overview+' => '',
'Menu:NewChange' => '新建变更',
'Menu:NewChange+' => '新建变更',
'Menu:SearchChanges' => '搜索变更',
'Menu:SearchChanges+' => '搜索变更',
'Menu:Change:Shortcuts' => '快捷方式',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => '等待审核的变更',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => '等待批准的变更',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => '所有打开的变更',
'Menu:Changes+' => '所有打开的变更',
'Menu:MyChanges' => '分配给我的变更',
'Menu:MyChanges+' => '分配给我的变更 (作为办理人)',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => '最近一周的变更 (按类型)',
'UI-ChangeManagementOverview-Last-7-days' => '最近一周的变更 (按数量)',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => '最近一周的变更 (按范围)',
'UI-ChangeManagementOverview-ChangeByStatus-last-7-days' => '最近一周的变更 (按状态)',
'Tickets:Related:OpenChanges' => '打开的变更',
'Tickets:Related:RecentChanges' => '最近的变更 (72小时)',
]);
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: Change
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:ApprovedChange' => '已批准的变更',
'Class:ApprovedChange+' => '',
'Class:ApprovedChange/Attribute:approval_comment' => '批准说明',
'Class:ApprovedChange/Attribute:approval_comment+' => '',
'Class:ApprovedChange/Attribute:approval_date' => '批准日期',
'Class:ApprovedChange/Attribute:approval_date+' => '',
'Class:ApprovedChange/Stimulus:ev_approve' => '批准',
'Class:ApprovedChange/Stimulus:ev_approve+' => '',
'Class:ApprovedChange/Stimulus:ev_assign' => '分配',
'Class:ApprovedChange/Stimulus:ev_assign+' => '',
'Class:ApprovedChange/Stimulus:ev_finish' => '完成',
'Class:ApprovedChange/Stimulus:ev_finish+' => '',
'Class:ApprovedChange/Stimulus:ev_implement' => '实施',
'Class:ApprovedChange/Stimulus:ev_implement+' => '',
'Class:ApprovedChange/Stimulus:ev_monitor' => '验收',
'Class:ApprovedChange/Stimulus:ev_monitor+' => '',
'Class:ApprovedChange/Stimulus:ev_notapprove' => '不批准',
'Class:ApprovedChange/Stimulus:ev_notapprove+' => '',
'Class:ApprovedChange/Stimulus:ev_plan' => '计划',
'Class:ApprovedChange/Stimulus:ev_plan+' => '',
'Class:ApprovedChange/Stimulus:ev_reject' => '驳回',
'Class:ApprovedChange/Stimulus:ev_reject+' => '',
'Class:ApprovedChange/Stimulus:ev_reopen' => '重新打开',
'Class:ApprovedChange/Stimulus:ev_reopen+' => '',
'Class:ApprovedChange/Stimulus:ev_replan' => '重新计划',
'Class:ApprovedChange/Stimulus:ev_replan+' => '',
'Class:ApprovedChange/Stimulus:ev_validate' => '同意',
'Class:ApprovedChange/Stimulus:ev_validate+' => '',
'Class:Change' => '变更',
'Class:Change+' => '',
'Class:Change/Attribute:child_changes_list' => '子变更',
'Class:Change/Attribute:child_changes_list+' => '此变更相关的字变更',
'Class:Change/Attribute:creation_date' => '创建时间',
'Class:Change/Attribute:creation_date+' => '',
'Class:Change/Attribute:fallback' => '回滚计划',
'Class:Change/Attribute:fallback+' => '',
'Class:Change/Attribute:impact' => '影响',
'Class:Change/Attribute:impact+' => '',
'Class:Change/Attribute:manager_email' => '邮箱',
'Class:Change/Attribute:manager_email+' => '',
'Class:Change/Attribute:manager_group_id' => '管理团队',
'Class:Change/Attribute:manager_group_id+' => '',
'Class:Change/Attribute:manager_group_name' => '管理团队名称',
'Class:Change/Attribute:manager_group_name+' => '',
'Class:Change/Attribute:manager_id' => '经理',
'Class:Change/Attribute:manager_id+' => '',
'Class:Change/Attribute:outage' => '停机',
'Class:Change/Attribute:outage+' => '',
'Class:Change/Attribute:outage/Value:no' => '否',
'Class:Change/Attribute:outage/Value:no+' => '',
'Class:Change/Attribute:outage/Value:yes' => '是',
'Class:Change/Attribute:outage/Value:yes+' => '',
'Class:Change/Attribute:parent_id' => '父级变更',
'Class:Change/Attribute:parent_id+' => '',
'Class:Change/Attribute:parent_id_finalclass_recall' => '变更类型',
'Class:Change/Attribute:parent_id_finalclass_recall+' => '',
'Class:Change/Attribute:parent_id_friendlyname' => '父级变更昵称',
'Class:Change/Attribute:parent_id_friendlyname+' => '',
'Class:Change/Attribute:parent_name' => '变更编号',
'Class:Change/Attribute:parent_name+' => '',
'Class:Change/Attribute:reason' => '驳回原因',
'Class:Change/Attribute:reason+' => '',
'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_request_list' => '相关需求',
'Class:Change/Attribute:related_request_list+' => '此变更相关的所有用户需求',
'Class:Change/Attribute:requestor_email' => '邮箱',
'Class:Change/Attribute:requestor_email+' => '',
'Class:Change/Attribute:requestor_id' => '发起人',
'Class:Change/Attribute:requestor_id+' => '',
'Class:Change/Attribute:status' => '状态',
'Class:Change/Attribute:status+' => '',
'Class:Change/Attribute:status/Value:approved' => '已批准',
'Class:Change/Attribute:status/Value:approved+' => '',
'Class:Change/Attribute:status/Value:new' => '新建',
'Class:Change/Attribute:status/Value:new+' => '',
'Class:Change/Attribute:status/Value:validated' => '已确认',
'Class:Change/Attribute:status/Value:validated+' => '',
'Class:Change/Attribute:status/Value:rejected' => '已驳回',
'Class:Change/Attribute:status/Value:rejected+' => '',
'Class:Change/Attribute:status/Value:assigned' => '已分配',
'Class:Change/Attribute:status/Value:assigned+' => '',
'Class:Change/Attribute:status/Value:closed' => '已关闭',
'Class:Change/Attribute:status/Value:closed+' => '',
'Class:Change/Attribute:status/Value:plannedscheduled' => '已计划和安排',
'Class:Change/Attribute:status/Value:plannedscheduled+' => '',
'Class:Change/Attribute:status/Value:approved' => '已批准',
'Class:Change/Attribute:status/Value:approved+' => '',
'Class:Change/Attribute:status/Value:notapproved' => '未批准',
'Class:Change/Attribute:status/Value:notapproved+' => '',
'Class:Change/Attribute:status/Value:implemented' => '已实施',
'Class:Change/Attribute:status/Value:implemented+' => '',
'Class:Change/Attribute:status/Value:monitored' => '已验收',
'Class:Change/Attribute:status/Value:monitored+' => '',
'Class:Change/Attribute:status/Value:new' => '新建',
'Class:Change/Attribute:status/Value:new+' => '',
'Class:Change/Attribute:status/Value:notapproved' => '未批准',
'Class:Change/Attribute:status/Value:notapproved+' => '',
'Class:Change/Attribute:status/Value:plannedscheduled' => '已计划和安排',
'Class:Change/Attribute:status/Value:plannedscheduled+' => '',
'Class:Change/Attribute:status/Value:rejected' => '已驳回',
'Class:Change/Attribute:status/Value:rejected+' => '',
'Class:Change/Attribute:status/Value:validated' => '已确认',
'Class:Change/Attribute:status/Value:validated+' => '',
'Class:Change/Attribute:supervisor_email' => '邮箱',
'Class:Change/Attribute:supervisor_email+' => '',
'Class:Change/Attribute:status/Value:closed' => '已关闭',
'Class:Change/Attribute:status/Value:closed+' => '',
'Class:Change/Attribute:reason' => '驳回原因',
'Class:Change/Attribute:reason+' => '',
'Class:Change/Attribute:requestor_id' => '发起人',
'Class:Change/Attribute:requestor_id+' => '',
'Class:Change/Attribute:requestor_email' => '邮箱',
'Class:Change/Attribute:requestor_email+' => '',
'Class:Change/Attribute:creation_date' => '创建时间',
'Class:Change/Attribute:creation_date+' => '',
'Class:Change/Attribute:impact' => '影响',
'Class:Change/Attribute:impact+' => '',
'Class:Change/Attribute:supervisor_group_id' => '监督团队',
'Class:Change/Attribute:supervisor_group_id+' => '',
'Class:Change/Attribute:supervisor_group_name' => '监督团队名称',
'Class:Change/Attribute:supervisor_group_name+' => '',
'Class:Change/Attribute:supervisor_id' => '监督人',
'Class:Change/Attribute:supervisor_id+' => '',
'Class:Change/Stimulus:ev_approve' => '批准',
'Class:Change/Stimulus:ev_approve+' => '',
'Class:Change/Attribute:supervisor_email' => '邮箱',
'Class:Change/Attribute:supervisor_email+' => '',
'Class:Change/Attribute:manager_group_id' => '管理团队',
'Class:Change/Attribute:manager_group_id+' => '',
'Class:Change/Attribute:manager_group_name' => '管理团队名称',
'Class:Change/Attribute:manager_group_name+' => '',
'Class:Change/Attribute:manager_id' => '经理',
'Class:Change/Attribute:manager_id+' => '',
'Class:Change/Attribute:manager_email' => '邮箱',
'Class:Change/Attribute:manager_email+' => '',
'Class:Change/Attribute:outage' => '停机',
'Class:Change/Attribute:outage+' => '',
'Class:Change/Attribute:outage/Value:no' => '否',
'Class:Change/Attribute:outage/Value:no+' => '',
'Class:Change/Attribute:outage/Value:yes' => '是',
'Class:Change/Attribute:outage/Value:yes+' => '',
'Class:Change/Attribute:fallback' => '回滚计划',
'Class:Change/Attribute:fallback+' => '',
'Class:Change/Attribute:parent_id' => '父级变更',
'Class:Change/Attribute:parent_id+' => '',
'Class:Change/Attribute:parent_name' => '变更编号',
'Class:Change/Attribute:parent_name+' => '',
'Class:Change/Attribute: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_incident_list' => '相关事件',
'Class:Change/Attribute:related_incident_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' => '变更类型',
'Class:Change/Attribute:parent_id_finalclass_recall+' => '',
'Class:Change/Stimulus:ev_validate' => '同意',
'Class:Change/Stimulus:ev_validate+' => '',
'Class:Change/Stimulus:ev_reject' => '驳回',
'Class:Change/Stimulus:ev_reject+' => '',
'Class:Change/Stimulus:ev_assign' => '分配',
'Class:Change/Stimulus:ev_assign+' => '',
'Class:Change/Stimulus:ev_finish' => '完成',
'Class:Change/Stimulus:ev_finish+' => '',
'Class:Change/Stimulus:ev_reopen' => '重新打开',
'Class:Change/Stimulus:ev_reopen+' => '',
'Class:Change/Stimulus:ev_plan' => '计划',
'Class:Change/Stimulus:ev_plan+' => '',
'Class:Change/Stimulus:ev_approve' => '批准',
'Class:Change/Stimulus:ev_approve+' => '',
'Class:Change/Stimulus:ev_replan' => '重新计划',
'Class:Change/Stimulus:ev_replan+' => '',
'Class:Change/Stimulus:ev_notapprove' => '不批准',
'Class:Change/Stimulus:ev_notapprove+' => '',
'Class:Change/Stimulus:ev_implement' => '实施',
'Class:Change/Stimulus:ev_implement+' => '',
'Class:Change/Stimulus:ev_monitor' => '验收',
'Class:Change/Stimulus:ev_monitor+' => '',
'Class:Change/Stimulus:ev_notapprove' => '不批准',
'Class:Change/Stimulus:ev_notapprove+' => '',
'Class:Change/Stimulus:ev_plan' => '计划',
'Class:Change/Stimulus:ev_plan+' => '',
'Class:Change/Stimulus:ev_reject' => '驳回',
'Class:Change/Stimulus:ev_reject+' => '',
'Class:Change/Stimulus:ev_reopen' => '重新打开',
'Class:Change/Stimulus:ev_reopen+' => '',
'Class:Change/Stimulus:ev_replan' => '重新计划',
'Class:Change/Stimulus:ev_replan+' => '',
'Class:Change/Stimulus:ev_validate' => '同意',
'Class:Change/Stimulus:ev_validate+' => '',
'Class:EmergencyChange' => '紧急变更',
'Class:EmergencyChange+' => '',
'Class:EmergencyChange/Stimulus:ev_approve' => '批准',
'Class:EmergencyChange/Stimulus:ev_approve+' => '',
'Class:EmergencyChange/Stimulus:ev_assign' => '分配',
'Class:EmergencyChange/Stimulus:ev_assign+' => '',
'Class:EmergencyChange/Stimulus:ev_finish' => '完成',
'Class:EmergencyChange/Stimulus:ev_finish+' => '',
'Class:EmergencyChange/Stimulus:ev_implement' => '实施',
'Class:EmergencyChange/Stimulus:ev_implement+' => '',
'Class:EmergencyChange/Stimulus:ev_monitor' => '验收',
'Class:EmergencyChange/Stimulus:ev_monitor+' => '',
'Class:EmergencyChange/Stimulus:ev_notapprove' => '不批准',
'Class:EmergencyChange/Stimulus:ev_notapprove+' => '',
'Class:EmergencyChange/Stimulus:ev_plan' => '计划',
'Class:EmergencyChange/Stimulus:ev_plan+' => '',
'Class:EmergencyChange/Stimulus:ev_reject' => '驳回',
'Class:EmergencyChange/Stimulus:ev_reject+' => '',
'Class:EmergencyChange/Stimulus:ev_reopen' => '重新打开',
'Class:EmergencyChange/Stimulus:ev_reopen+' => '',
'Class:EmergencyChange/Stimulus:ev_replan' => '重新计划',
'Class:EmergencyChange/Stimulus:ev_replan+' => '',
'Class:EmergencyChange/Stimulus:ev_validate' => '同意',
'Class:EmergencyChange/Stimulus:ev_validate+' => '',
'Class:NormalChange' => '正常变更',
'Class:NormalChange+' => '',
'Class:NormalChange/Attribute:acceptance_comment' => '审核说明',
'Class:NormalChange/Attribute:acceptance_comment+' => '',
'Class:NormalChange/Attribute:acceptance_date' => '审核日期',
'Class:NormalChange/Attribute:acceptance_date+' => '',
'Class:NormalChange/Stimulus:ev_approve' => '批准',
'Class:NormalChange/Stimulus:ev_approve+' => '',
'Class:NormalChange/Stimulus:ev_assign' => '分配',
'Class:NormalChange/Stimulus:ev_assign+' => '',
'Class:NormalChange/Stimulus:ev_finish' => '完成',
'Class:NormalChange/Stimulus:ev_finish+' => '',
'Class:NormalChange/Stimulus:ev_implement' => '实施',
'Class:NormalChange/Stimulus:ev_implement+' => '',
'Class:NormalChange/Stimulus:ev_monitor' => '验收',
'Class:NormalChange/Stimulus:ev_monitor+' => '',
'Class:NormalChange/Stimulus:ev_notapprove' => '不批准',
'Class:NormalChange/Stimulus:ev_notapprove+' => '',
'Class:NormalChange/Stimulus:ev_plan' => '计划',
'Class:NormalChange/Stimulus:ev_plan+' => '',
'Class:NormalChange/Stimulus:ev_reject' => '驳回',
'Class:NormalChange/Stimulus:ev_reject+' => '',
'Class:NormalChange/Stimulus:ev_reopen' => '重新打开',
'Class:NormalChange/Stimulus:ev_reopen+' => '',
'Class:NormalChange/Stimulus:ev_replan' => '重新计划',
'Class:NormalChange/Stimulus:ev_replan+' => '',
'Class:NormalChange/Stimulus:ev_validate' => '同意',
'Class:NormalChange/Stimulus:ev_validate+' => '',
'Class:Change/Stimulus:ev_finish' => '完成',
'Class:Change/Stimulus:ev_finish+' => '',
]);
//
// Class: RoutineChange
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:RoutineChange' => '例行变更',
'Class:RoutineChange+' => '',
'Class:RoutineChange/Stimulus:ev_approve' => '批准',
'Class:RoutineChange/Stimulus:ev_approve+' => '',
'Class:RoutineChange/Stimulus:ev_validate' => '同意',
'Class:RoutineChange/Stimulus:ev_validate+' => '',
'Class:RoutineChange/Stimulus:ev_reject' => '驳回',
'Class:RoutineChange/Stimulus:ev_reject+' => '',
'Class:RoutineChange/Stimulus:ev_assign' => '分配',
'Class:RoutineChange/Stimulus:ev_assign+' => '',
'Class:RoutineChange/Stimulus:ev_finish' => '完成',
'Class:RoutineChange/Stimulus:ev_finish+' => '',
'Class:RoutineChange/Stimulus:ev_reopen' => '重新打开',
'Class:RoutineChange/Stimulus:ev_reopen+' => '',
'Class:RoutineChange/Stimulus:ev_plan' => '计划',
'Class:RoutineChange/Stimulus:ev_plan+' => '',
'Class:RoutineChange/Stimulus:ev_approve' => '批准',
'Class:RoutineChange/Stimulus:ev_approve+' => '',
'Class:RoutineChange/Stimulus:ev_replan' => '重新计划',
'Class:RoutineChange/Stimulus:ev_replan+' => '',
'Class:RoutineChange/Stimulus:ev_notapprove' => '不批准',
'Class:RoutineChange/Stimulus:ev_notapprove+' => '',
'Class:RoutineChange/Stimulus:ev_implement' => '实施',
'Class:RoutineChange/Stimulus:ev_implement+' => '',
'Class:RoutineChange/Stimulus:ev_monitor' => '验收',
'Class:RoutineChange/Stimulus:ev_monitor+' => '',
'Class:RoutineChange/Stimulus:ev_notapprove' => '不批准',
'Class:RoutineChange/Stimulus:ev_notapprove+' => '',
'Class:RoutineChange/Stimulus:ev_plan' => '计划',
'Class:RoutineChange/Stimulus:ev_plan+' => '',
'Class:RoutineChange/Stimulus:ev_reject' => '驳回',
'Class:RoutineChange/Stimulus:ev_reject+' => '',
'Class:RoutineChange/Stimulus:ev_reopen' => '重新打开',
'Class:RoutineChange/Stimulus:ev_reopen+' => '',
'Class:RoutineChange/Stimulus:ev_replan' => '重新计划',
'Class:RoutineChange/Stimulus:ev_replan+' => '',
'Class:RoutineChange/Stimulus:ev_validate' => '同意',
'Class:RoutineChange/Stimulus:ev_validate+' => '',
'Menu:Change:Overview' => '概况',
'Menu:Change:Overview+' => '',
'Menu:Change:Shortcuts' => '快捷方式',
'Menu:Change:Shortcuts+' => '',
'Menu:ChangeManagement' => '变更管理',
'Menu:Changes' => '所有打开的变更',
'Menu:Changes+' => '所有打开的变更',
'Menu:MyChanges' => '分配给我的变更',
'Menu:MyChanges+' => '分配给我的变更 (作为办理人)',
'Menu:NewChange' => '新建变更',
'Menu:NewChange+' => '新建变更',
'Menu:SearchChanges' => '搜索变更',
'Menu:SearchChanges+' => '搜索变更',
'Menu:WaitingAcceptance' => '等待审核的变更',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => '等待批准的变更',
'Menu:WaitingApproval+' => '',
'Tickets:Related:OpenChanges' => '打开的变更',
'Tickets:Related:RecentChanges' => '最近的变更 (72小时)',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => '最近一周的变更 (按类型)',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => '最近一周的变更 (按范围)',
'UI-ChangeManagementOverview-ChangeByStatus-last-7-days' => '最近一周的变更 (按状态)',
'UI-ChangeManagementOverview-Last-7-days' => '最近一周的变更 (按数量)',
'Class:RoutineChange/Stimulus:ev_finish' => '完成',
'Class:RoutineChange/Stimulus:ev_finish+' => '',
]);
//
// Class: ApprovedChange
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:ApprovedChange' => '已批准的变更',
'Class:ApprovedChange+' => '',
'Class:ApprovedChange/Attribute:approval_date' => '批准日期',
'Class:ApprovedChange/Attribute:approval_date+' => '',
'Class:ApprovedChange/Attribute:approval_comment' => '批准说明',
'Class:ApprovedChange/Attribute:approval_comment+' => '',
'Class:ApprovedChange/Stimulus:ev_validate' => '同意',
'Class:ApprovedChange/Stimulus:ev_validate+' => '',
'Class:ApprovedChange/Stimulus:ev_reject' => '驳回',
'Class:ApprovedChange/Stimulus:ev_reject+' => '',
'Class:ApprovedChange/Stimulus:ev_assign' => '分配',
'Class:ApprovedChange/Stimulus:ev_assign+' => '',
'Class:ApprovedChange/Stimulus:ev_reopen' => '重新打开',
'Class:ApprovedChange/Stimulus:ev_reopen+' => '',
'Class:ApprovedChange/Stimulus:ev_plan' => '计划',
'Class:ApprovedChange/Stimulus:ev_plan+' => '',
'Class:ApprovedChange/Stimulus:ev_approve' => '批准',
'Class:ApprovedChange/Stimulus:ev_approve+' => '',
'Class:ApprovedChange/Stimulus:ev_replan' => '重新计划',
'Class:ApprovedChange/Stimulus:ev_replan+' => '',
'Class:ApprovedChange/Stimulus:ev_notapprove' => '不批准',
'Class:ApprovedChange/Stimulus:ev_notapprove+' => '',
'Class:ApprovedChange/Stimulus:ev_implement' => '实施',
'Class:ApprovedChange/Stimulus:ev_implement+' => '',
'Class:ApprovedChange/Stimulus:ev_monitor' => '验收',
'Class:ApprovedChange/Stimulus:ev_monitor+' => '',
'Class:ApprovedChange/Stimulus:ev_finish' => '完成',
'Class:ApprovedChange/Stimulus:ev_finish+' => '',
]);
//
// Class: NormalChange
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:NormalChange' => '正常变更',
'Class:NormalChange+' => '',
'Class:NormalChange/Attribute:acceptance_date' => '审核日期',
'Class:NormalChange/Attribute:acceptance_date+' => '',
'Class:NormalChange/Attribute:acceptance_comment' => '审核说明',
'Class:NormalChange/Attribute:acceptance_comment+' => '',
'Class:NormalChange/Stimulus:ev_validate' => '同意',
'Class:NormalChange/Stimulus:ev_validate+' => '',
'Class:NormalChange/Stimulus:ev_reject' => '驳回',
'Class:NormalChange/Stimulus:ev_reject+' => '',
'Class:NormalChange/Stimulus:ev_assign' => '分配',
'Class:NormalChange/Stimulus:ev_assign+' => '',
'Class:NormalChange/Stimulus:ev_reopen' => '重新打开',
'Class:NormalChange/Stimulus:ev_reopen+' => '',
'Class:NormalChange/Stimulus:ev_plan' => '计划',
'Class:NormalChange/Stimulus:ev_plan+' => '',
'Class:NormalChange/Stimulus:ev_approve' => '批准',
'Class:NormalChange/Stimulus:ev_approve+' => '',
'Class:NormalChange/Stimulus:ev_replan' => '重新计划',
'Class:NormalChange/Stimulus:ev_replan+' => '',
'Class:NormalChange/Stimulus:ev_notapprove' => '不批准',
'Class:NormalChange/Stimulus:ev_notapprove+' => '',
'Class:NormalChange/Stimulus:ev_implement' => '实施',
'Class:NormalChange/Stimulus:ev_implement+' => '',
'Class:NormalChange/Stimulus:ev_monitor' => '验收',
'Class:NormalChange/Stimulus:ev_monitor+' => '',
'Class:NormalChange/Stimulus:ev_finish' => '完成',
'Class:NormalChange/Stimulus:ev_finish+' => '',
]);
//
// Class: EmergencyChange
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:EmergencyChange' => '紧急变更',
'Class:EmergencyChange+' => '',
'Class:EmergencyChange/Stimulus:ev_validate' => '同意',
'Class:EmergencyChange/Stimulus:ev_validate+' => '',
'Class:EmergencyChange/Stimulus:ev_reject' => '驳回',
'Class:EmergencyChange/Stimulus:ev_reject+' => '',
'Class:EmergencyChange/Stimulus:ev_assign' => '分配',
'Class:EmergencyChange/Stimulus:ev_assign+' => '',
'Class:EmergencyChange/Stimulus:ev_reopen' => '重新打开',
'Class:EmergencyChange/Stimulus:ev_reopen+' => '',
'Class:EmergencyChange/Stimulus:ev_plan' => '计划',
'Class:EmergencyChange/Stimulus:ev_plan+' => '',
'Class:EmergencyChange/Stimulus:ev_approve' => '批准',
'Class:EmergencyChange/Stimulus:ev_approve+' => '',
'Class:EmergencyChange/Stimulus:ev_replan' => '重新计划',
'Class:EmergencyChange/Stimulus:ev_replan+' => '',
'Class:EmergencyChange/Stimulus:ev_notapprove' => '不批准',
'Class:EmergencyChange/Stimulus:ev_notapprove+' => '',
'Class:EmergencyChange/Stimulus:ev_implement' => '实施',
'Class:EmergencyChange/Stimulus:ev_implement+' => '',
'Class:EmergencyChange/Stimulus:ev_monitor' => '验收',
'Class:EmergencyChange/Stimulus:ev_monitor+' => '',
'Class:EmergencyChange/Stimulus:ev_finish' => '完成',
'Class:EmergencyChange/Stimulus:ev_finish+' => '',
]);

View File

@@ -4,16 +4,81 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Menu:ChangeManagement' => '变更管理',
'Menu:Change:Overview' => '概况',
'Menu:Change:Overview+' => '',
'Menu:NewChange' => '新建变更',
'Menu:NewChange+' => '新建变更',
'Menu:SearchChanges' => '搜索变更',
'Menu:SearchChanges+' => '搜索变更',
'Menu:Change:Shortcuts' => '快捷方式',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => '等待审核的变更',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => '等待批准的变更',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => '所有打开的变更',
'Menu:Changes+' => '所有打开的变更',
'Menu:MyChanges' => '分配给我的变更',
'Menu:MyChanges+' => '分配给我的变更 (作为办理人)',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => '最近一周的变更 (按类型)',
'UI-ChangeManagementOverview-Last-7-days' => '最近一周的变更 (按数量)',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => '最近一周的变更 (按范围)',
'UI-ChangeManagementOverview-ChangeByStatus-last-7-days' => '最近一周的变更 (按状态)',
'Tickets:Related:OpenChanges' => '打开的变更',
'Tickets:Related:RecentChanges' => '最近的变更 (72小时)',
]);
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: Change
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:Change' => '变更',
'Class:Change+' => '',
'Class:Change/Attribute:approval_date' => '审批日期',
'Class:Change/Attribute:approval_date+' => '',
'Class:Change/Attribute:status' => '状态',
'Class:Change/Attribute:status+' => '',
'Class:Change/Attribute:status/Value:new' => '新建',
'Class:Change/Attribute:status/Value:new+' => '',
'Class:Change/Attribute:status/Value:assigned' => '已分配',
'Class:Change/Attribute:status/Value:assigned+' => '',
'Class:Change/Attribute:status/Value:planned' => '已计划',
'Class:Change/Attribute:status/Value:planned+' => '',
'Class:Change/Attribute:status/Value:rejected' => '已驳回',
'Class:Change/Attribute:status/Value:rejected+' => '',
'Class:Change/Attribute:status/Value:approved' => '已批准',
'Class:Change/Attribute:status/Value:approved+' => '',
'Class:Change/Attribute:status/Value:closed' => '已关闭',
'Class:Change/Attribute:status/Value:closed+' => '',
'Class:Change/Attribute:category' => '类型',
'Class:Change/Attribute:category+' => '',
'Class:Change/Attribute:category/Value:application' => '应用',
@@ -28,83 +93,48 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:Change/Attribute:category/Value:software+' => '软件',
'Class:Change/Attribute:category/Value:system' => '系统',
'Class:Change/Attribute:category/Value:system+' => '系统',
'Class:Change/Attribute:changemanager_email' => '邮箱',
'Class:Change/Attribute:changemanager_email+' => '',
'Class:Change/Attribute:changemanager_id' => '变更经理',
'Class:Change/Attribute:changemanager_id+' => '',
'Class:Change/Attribute:child_changes_list' => '子变更',
'Class:Change/Attribute:child_changes_list+' => '此变更相关的所有子变更',
'Class:Change/Attribute:creation_date' => '创建日期',
'Class:Change/Attribute:creation_date+' => '',
'Class:Change/Attribute:fallback_plan' => '回滚计划',
'Class:Change/Attribute:fallback_plan+' => '',
'Class:Change/Attribute:outage' => '停机',
'Class:Change/Attribute:outage+' => '',
'Class:Change/Attribute:outage/Value:no' => '否',
'Class:Change/Attribute:outage/Value:no+' => '',
'Class:Change/Attribute:outage/Value:yes' => '是',
'Class:Change/Attribute:outage/Value:yes+' => '',
'Class:Change/Attribute:parent_id' => '父级变更',
'Class:Change/Attribute:parent_id+' => '',
'Class:Change/Attribute:parent_id_friendlyname' => '父级变更昵称',
'Class:Change/Attribute:parent_id_friendlyname+' => '',
'Class:Change/Attribute:parent_name' => '变更编号',
'Class:Change/Attribute:parent_name+' => '',
'Class:Change/Attribute:reject_reason' => '驳回原因',
'Class:Change/Attribute:reject_reason+' => '',
'Class:Change/Attribute:changemanager_id' => '变更经理',
'Class:Change/Attribute:changemanager_id+' => '',
'Class:Change/Attribute:changemanager_email' => '邮箱',
'Class:Change/Attribute:changemanager_email+' => '',
'Class:Change/Attribute:parent_id' => '父级变更',
'Class:Change/Attribute:parent_id+' => '',
'Class:Change/Attribute:parent_name' => '变更编号',
'Class:Change/Attribute:parent_name+' => '',
'Class:Change/Attribute:creation_date' => '创建日期',
'Class:Change/Attribute:creation_date+' => '',
'Class:Change/Attribute:approval_date' => '审批日期',
'Class:Change/Attribute:approval_date+' => '',
'Class:Change/Attribute:fallback_plan' => '回滚计划',
'Class:Change/Attribute:fallback_plan+' => '',
'Class:Change/Attribute:related_request_list' => '相关需求',
'Class:Change/Attribute:related_request_list+' => '此变更相关的所有用户需求',
'Class:Change/Attribute:related_incident_list' => '相关事件',
'Class:Change/Attribute:related_incident_list+' => '此变更相关的所有事件',
'Class:Change/Attribute:related_problems_list' => '相关问题',
'Class:Change/Attribute:related_problems_list+' => '此变更相关的所有问题',
'Class:Change/Attribute:related_request_list' => '相关需求',
'Class:Change/Attribute:related_request_list+' => '此变更相关的所有用户需求',
'Class:Change/Attribute:status' => '状态',
'Class:Change/Attribute:status+' => '',
'Class:Change/Attribute:status/Value:approved' => '已批准',
'Class:Change/Attribute:status/Value:approved+' => '',
'Class:Change/Attribute:status/Value:assigned' => '已分配',
'Class:Change/Attribute:status/Value:assigned+' => '',
'Class:Change/Attribute:status/Value:closed' => '已关闭',
'Class:Change/Attribute:status/Value:closed+' => '',
'Class:Change/Attribute:status/Value:new' => '新建',
'Class:Change/Attribute:status/Value:new+' => '',
'Class:Change/Attribute:status/Value:planned' => '已计划',
'Class:Change/Attribute:status/Value:planned+' => '',
'Class:Change/Attribute:status/Value:rejected' => '已驳回',
'Class:Change/Attribute:status/Value:rejected+' => '',
'Class:Change/Stimulus:ev_approve' => '批准',
'Class:Change/Stimulus:ev_approve+' => '',
'Class:Change/Attribute:child_changes_list' => '子变更',
'Class:Change/Attribute:child_changes_list+' => '此变更相关的所有子变更',
'Class:Change/Attribute:parent_id_friendlyname' => '父级变更昵称',
'Class:Change/Attribute:parent_id_friendlyname+' => '',
'Class:Change/Stimulus:ev_assign' => '分配',
'Class:Change/Stimulus:ev_assign+' => '',
'Class:Change/Stimulus:ev_finish' => '关闭',
'Class:Change/Stimulus:ev_finish+' => '',
'Class:Change/Stimulus:ev_plan' => '计划',
'Class:Change/Stimulus:ev_plan+' => '',
'Class:Change/Stimulus:ev_reject' => '驳回',
'Class:Change/Stimulus:ev_reject+' => '',
'Class:Change/Stimulus:ev_reopen' => '重新打开',
'Class:Change/Stimulus:ev_reopen+' => '',
'Menu:Change:Overview' => '概况',
'Menu:Change:Overview+' => '',
'Menu:Change:Shortcuts' => '快捷方式',
'Menu:Change:Shortcuts+' => '',
'Menu:ChangeManagement' => '变更管理',
'Menu:Changes' => '所有打开的变更',
'Menu:Changes+' => '所有打开的变更',
'Menu:MyChanges' => '分配给我的变更',
'Menu:MyChanges+' => '分配给我的变更 (作为办理人)',
'Menu:NewChange' => '新建变更',
'Menu:NewChange+' => '新建变更',
'Menu:SearchChanges' => '搜索变更',
'Menu:SearchChanges+' => '搜索变更',
'Menu:WaitingAcceptance' => '等待审核的变更',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => '等待批准的变更',
'Menu:WaitingApproval+' => '',
'Tickets:Related:OpenChanges' => '打开的变更',
'Tickets:Related:RecentChanges' => '最近的变更 (72小时)',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => '最近一周的变更 (按类型)',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => '最近一周的变更 (按范围)',
'UI-ChangeManagementOverview-ChangeByStatus-last-7-days' => '最近一周的变更 (按状态)',
'UI-ChangeManagementOverview-Last-7-days' => '最近一周的变更 (按数量)',
'Class:Change/Stimulus:ev_approve' => '批准',
'Class:Change/Stimulus:ev_approve+' => '',
'Class:Change/Stimulus:ev_finish' => '关闭',
'Class:Change/Stimulus:ev_finish+' => '',
'Class:Change/Attribute:outage' => '停机',
'Class:Change/Attribute:outage+' => '',
'Class:Change/Attribute:outage/Value:no' => '',
'Class:Change/Attribute:outage/Value:no+' => '',
'Class:Change/Attribute:outage/Value:yes' => '是',
'Class:Change/Attribute:outage/Value:yes+' => '',
]);

View File

@@ -4,27 +4,40 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Menu:ConfigEditor' => '编辑配置文件',
'config-edit-title' => '配置文件编辑器',
'config-edit-intro' => '编辑配置文件时请务必格外小心.',
'config-apply' => '应用',
'config-apply-title' => '应用 (Ctrl+S)',
'config-cancel' => '重置',
'config-confirm-cancel' => '您的修改将被丢弃.',
'config-current-line' => '正在编辑第%1$s行',
'config-edit-intro' => '编辑配置文件时请务必格外小心.',
'config-edit-title' => '配置文件编辑器',
'config-error-file-changed' => '错误: 配置文件在您打开以后已被更改, 无法保存. 请刷新并再次保存.',
'config-error-transaction' => '错误: 无效的事务编号. 配置<b>没有</b>被更新.',
'config-interactive-not-allowed' => ITOP_APPLICATION_SHORT.'交互式配置编辑器已禁用. 请在配置文件中查看 <code>\'config_editor\' => \'disabled\'</code>.',
'config-no-change' => '没有变化: 配置文件将保持不变.',
'config-not-allowed-in-demo' => '抱歉, '.ITOP_APPLICATION_SHORT.'处于<b>演示模式</b>: 不能编辑配置文件.',
'config-parse-error' => '第%2$d行: %1$s.<br/>配置文件尚未更新.',
'config-reverted' => '配置文件已恢复.',
'config-saved' => '保存成功.',
'config-confirm-cancel' => '您的修改将被丢弃.',
'config-no-change' => '没有变化: 配置文件将保持不变.',
'config-reverted' => '配置文件已恢复.',
'config-parse-error' => '第%2$d行: %1$s.<br/>配置文件尚未更新.',
'config-current-line' => '正在编辑第%1$s行',
'config-saved-warning-db-password' => '保存成功, 但因为数据库密码中包含不支持的字符, 配置文件备份不会成功.',
'config-error-transaction' => '错误: 无效的事务编号. 配置<b>没有</b>被更新.',
'config-error-file-changed' => '错误: 配置文件在您打开以后已被更改, 无法保存. 请刷新并再次保存.',
'config-not-allowed-in-demo' => '抱歉, '.ITOP_APPLICATION_SHORT.'处于<b>演示模式</b>: 不能编辑配置文件.',
'config-interactive-not-allowed' => ITOP_APPLICATION_SHORT.'交互式配置编辑器已禁用. 请在配置文件中查看 <code>\'config_editor\' => \'disabled\'</code>.',
]);

View File

@@ -4,94 +4,123 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:ModuleInstallation/Attribute:comment' => '备注',
'Class:ModuleInstallation/Attribute:installed' => '安装时间',
'Class:ModuleInstallation/Attribute:name' => '名称',
'Class:ModuleInstallation/Attribute:version' => '版本',
'Menu:iTopUpdate' => '应用升级',
'Menu:iTopUpdate+' => '应用升级',
'iTopUpdate:Error:BadFileContent' => '升级文件不是程序升级包',
'iTopUpdate:Error:BadFileFormat' => '上传的不是zip格式的文件',
'iTopUpdate:Error:BadItopProduct' => '升级文件与您的系统不兼容',
'iTopUpdate:Error:Copy' => '错误, 无法复制 \'%1$s\' 到 \'%2$s\'',
'iTopUpdate:Error:CorruptedFile' => '文件%1$s已损坏',
'iTopUpdate:Error:FileNotFound' => '文件找不到',
'iTopUpdate:Error:FileUploadMaxSizeTooSmall' => '上传上限太小. 请调整PHP配置.',
'iTopUpdate:Error:InvalidToken' => '无效的token',
'iTopUpdate:Error:MissingFile' => '缺少文件: %1$s',
'iTopUpdate:Error:MissingFunction' => '无法开始升级, 功能缺失',
'iTopUpdate:Error:NoFile' => '没有提供文件',
'iTopUpdate:Error:UpdateFailed' => '升级失败',
'iTopUpdate:UI:Action' => '升级',
'iTopUpdate:UI:Back' => '返回',
'iTopUpdate:UI:Backup' => '升级之前执行备份',
'iTopUpdate:UI:CanCoreUpdate:Error' => '文件系统检查失败 (%1$s)',
'iTopUpdate:UI:CanCoreUpdate:ErrorFileNotExist' => '文件系统检查失败 (%1$s文件不存在)',
'iTopUpdate:UI:CanCoreUpdate:Failed' => '文件系统检查失败',
'iTopUpdate:UI:CanCoreUpdate:Loading' => '正在文件系统',
'iTopUpdate:UI:CanCoreUpdate:No' => '应用无法升级: %1$s',
'iTopUpdate:UI:CanCoreUpdate:Warning' => '警告: 应用升级可能失败: %1$s',
'iTopUpdate:UI:CanCoreUpdate:Yes' => '应用无法升级',
'iTopUpdate:UI:Cancel' => '取消',
'iTopUpdate:UI:CannotUpdateUseSetup' => '<b>检测到一些文件被修改</b>, 无法进行局部升级.</br>请按照<a target="_blank" href="%2$s">指南</a>一步步操作以手动升级系统. 您必须使用<a href="%1$s">安装</a>已升级应用.',
'iTopUpdate:UI:CheckInProgress' => '完整性检查中, 请稍后',
'iTopUpdate:UI:CheckUpdate' => '校验升级文件',
'iTopUpdate:UI:ConfirmInstallFile' => '即将安装%1$s',
'iTopUpdate:UI:Continue' => '继续',
'iTopUpdate:UI:CurrentVersion' => '当前版本',
'iTopUpdate:UI:DBDiskSpace' => '数据库的磁盘空间',
'iTopUpdate:UI:DiskFreeSpace' => '磁盘剩余空间',
'iTopUpdate:UI:DoBackup:Label' => '备份文件和数据库',
'iTopUpdate:UI:DoBackup:Warning' => '由于磁盘空间不足, 不建议备份',
'iTopUpdate:UI:DoFilesArchive' => '打包应用文件',
'iTopUpdate:UI:DoUpdate' => '升级',
'iTopUpdate:UI:FileUploadMaxSize' => '文件上传大小上限',
'iTopUpdate:UI:History' => '版本历史',
'iTopUpdate:UI:ItopDiskSpace' => ITOP_APPLICATION_SHORT.'的磁盘空间',
'iTopUpdate:UI:MaintenanceModeActive' => '此应用当前维护中, 不允许任何用户访问. 必须运行安装或恢复归档来使其处于正常模式.',
'iTopUpdate:UI:NewVersion' => '新安装的版本',
'iTopUpdate:UI:PageTitle' => '应用升级',
'iTopUpdate:UI:PostMaxSize' => 'PHP ini值post_max_size: %1$s',
'iTopUpdate:UI:Progress' => '升级进度',
'iTopUpdate:UI:RestoreArchive' => '您可以从归档文件 \'%1$s\' 还原应用程序',
'iTopUpdate:UI:RestoreBackup' => '您可以从 \'%1$s\' 还原数据库',
'iTopUpdate:UI:RunSetup' => '运行向导',
'itop-core-update:UI:SelectUpdateFile' => '应用升级',
'itop-core-update:UI:ConfirmUpdate' => ' 升级',
'itop-core-update:UI:UpdateCoreFiles' => '应用升级',
'iTopUpdate:UI:MaintenanceModeActive' => '此应用当前维护中, 不允许任何用户访问. 必须运行安装或恢复归档来使其处于正常模式.',
'itop-core-update:UI:UpdateDone' => '应用升级',
'itop-core-update/Operation:SelectUpdateFile/Title' => '应用升级',
'itop-core-update/Operation:ConfirmUpdate/Title' => '请确认升级应用',
'itop-core-update/Operation:UpdateCoreFiles/Title' => '应用正在升级',
'itop-core-update/Operation:UpdateDone/Title' => '应用升级完毕',
'iTopUpdate:UI:SelectUpdateFile' => '请选择要上传的升级文件',
'iTopUpdate:UI:ServerFile' => '服务器上的软件包路径已存在',
'iTopUpdate:UI:Setup' => ITOP_APPLICATION_SHORT.'安装',
'iTopUpdate:UI:SetupLaunch' => '启动'.ITOP_APPLICATION_SHORT.'安装',
'iTopUpdate:UI:SetupLaunchConfirm' => '将启动'.ITOP_APPLICATION_SHORT.'安装, 确定吗?',
'iTopUpdate:UI:FastSetupLaunch' => 'Fast Setup~~',
'iTopUpdate:UI:SetupMessage:Backup' => '数据库备份',
'iTopUpdate:UI:SetupMessage:CheckCompile' => '检查更新',
'iTopUpdate:UI:SetupMessage:Compile' => '升级应用程序和数据库',
'iTopUpdate:UI:SetupMessage:CopyFiles' => '复制新文件',
'iTopUpdate:UI:SetupMessage:EnterMaintenance' => '正在进入维护模式',
'iTopUpdate:UI:SetupMessage:ExitMaintenance' => '正在退出维护模式',
'iTopUpdate:UI:SetupMessage:FilesArchive' => '打包应用文件',
'iTopUpdate:UI:SetupMessage:Ready' => '准备开始',
'iTopUpdate:UI:SetupMessage:UpdateDatabase' => '升级数据库',
'iTopUpdate:UI:SetupMessage:UpdateDone' => '升级完成',
'iTopUpdate:UI:Status' => '状态',
'iTopUpdate:UI:UpdateDone' => '升级成功',
'iTopUpdate:UI:UploadArchive' => '请选择要上传的软件包',
'iTopUpdate:UI:UploadMaxFileSize' => 'PHP ini值upload_max_filesize: %1$s',
'iTopUpdate:UI:WarningReadOnlyDuringUpdate' => '升级期间, 应用会变成只读状态.',
'iTopUpdate:UI:CheckUpdate' => '校验升级文件',
'iTopUpdate:UI:ConfirmInstallFile' => '即将安装 %1$s',
'iTopUpdate:UI:DoUpdate' => '升级',
'iTopUpdate:UI:CurrentVersion' => '当前版本',
'iTopUpdate:UI:NewVersion' => '新安装的版本',
'iTopUpdate:UI:Back' => '返回',
'iTopUpdate:UI:Cancel' => '取消',
'iTopUpdate:UI:Continue' => '继续',
'iTopUpdate:UI:RunSetup' => '运行向导',
'iTopUpdate:UI:WithDBBackup' => '数据库备份',
'iTopUpdate:UI:WithFilesBackup' => '应用文件备份',
'iTopUpdate:UI:WithoutBackup' => '无需备份',
'itop-core-update/Operation:ConfirmUpdate/Title' => '请确认升级应用',
'itop-core-update/Operation:SelectUpdateFile/Title' => '应用升级',
'itop-core-update/Operation:UpdateCoreFiles/Title' => '应用正在升级',
'itop-core-update/Operation:UpdateDone/Title' => '应用升级完毕',
'itop-core-update:UI:ConfirmUpdate' => ' 升级',
'itop-core-update:UI:SelectUpdateFile' => '应用升级',
'itop-core-update:UI:UpdateCoreFiles' => '应用升级',
'itop-core-update:UI:UpdateDone' => '应用升级',
'iTopUpdate:UI:Backup' => '升级之前执行备份',
'iTopUpdate:UI:DoFilesArchive' => '打包应用文件',
'iTopUpdate:UI:UploadArchive' => '请选择要上传的软件包',
'iTopUpdate:UI:ServerFile' => '服务器上的软件包路径已存在',
'iTopUpdate:UI:WarningReadOnlyDuringUpdate' => '升级期间, 应用会变成只读状态.',
'iTopUpdate:UI:Status' => '状态',
'iTopUpdate:UI:Action' => '升级',
'iTopUpdate:UI:Setup' => ITOP_APPLICATION_SHORT.'安装',
'iTopUpdate:UI:History' => '版本历史',
'iTopUpdate:UI:Progress' => '升级进度',
'iTopUpdate:UI:DoBackup:Label' => '备份文件和数据库',
'iTopUpdate:UI:DoBackup:Warning' => '由于磁盘空间不足, 不建议备份',
'iTopUpdate:UI:DiskFreeSpace' => '磁盘剩余空间',
'iTopUpdate:UI:ItopDiskSpace' => ITOP_APPLICATION_SHORT.'的磁盘空间',
'iTopUpdate:UI:DBDiskSpace' => '数据库的磁盘空间',
'iTopUpdate:UI:FileUploadMaxSize' => '文件上传大小上限',
'iTopUpdate:UI:PostMaxSize' => 'PHP ini值post_max_size: %1$s',
'iTopUpdate:UI:UploadMaxFileSize' => 'PHP ini 值 upload_max_filesize: %1$s',
'iTopUpdate:UI:CanCoreUpdate:Loading' => '正在检查文件',
'iTopUpdate:UI:CanCoreUpdate:Error' => '文件检查失败 (%1$s)',
'iTopUpdate:UI:CanCoreUpdate:ErrorFileNotExist' => '文件检查失败 (%1$s 文件不存在)',
'iTopUpdate:UI:CanCoreUpdate:Failed' => '文件检查失败',
'iTopUpdate:UI:CanCoreUpdate:Yes' => '应用可以升级',
'iTopUpdate:UI:CanCoreUpdate:No' => '应用无法升级: %1$s',
'iTopUpdate:UI:CanCoreUpdate:Warning' => '警告: 应用升级可能失败: %1$s',
'iTopUpdate:UI:CannotUpdateUseSetup' => '<b>检测到一些文件被修改</b>, 无法进行局部升级.</br>请按照<a target="_blank" href="%2$s">指南</a>一步步操作以手动升级系统. 您必须使用<a href="%1$s">安装</a>已升级应用.',
'iTopUpdate:UI:CheckInProgress' => '完整性检查中, 请稍候',
'iTopUpdate:UI:SetupLaunch' => '启动'.ITOP_APPLICATION_SHORT.'安装',
'iTopUpdate:UI:SetupLaunchConfirm' => '将启动'.ITOP_APPLICATION_SHORT.'安装, 确定吗?',
// Setup Messages
'iTopUpdate:UI:SetupMessage:Ready' => '准备开始',
'iTopUpdate:UI:SetupMessage:EnterMaintenance' => '正在进入维护模式',
'iTopUpdate:UI:SetupMessage:Backup' => '数据库备份',
'iTopUpdate:UI:SetupMessage:FilesArchive' => '打包应用文件',
'iTopUpdate:UI:SetupMessage:CopyFiles' => '复制新文件',
'iTopUpdate:UI:SetupMessage:CheckCompile' => '检查更新',
'iTopUpdate:UI:SetupMessage:Compile' => '升级应用程序和数据库',
'iTopUpdate:UI:SetupMessage:UpdateDatabase' => '升级数据库',
'iTopUpdate:UI:SetupMessage:ExitMaintenance' => '正在退出维护模式',
'iTopUpdate:UI:SetupMessage:UpdateDone' => '升级完成',
// Errors
'iTopUpdate:Error:MissingFunction' => '无法开始升级, 功能缺失',
'iTopUpdate:Error:MissingFile' => '缺少文件: %1$s',
'iTopUpdate:Error:CorruptedFile' => '文件 %1$s 已损坏',
'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:UpdateFailed' => '升级失败',
'iTopUpdate:Error:FileUploadMaxSizeTooSmall' => '上传上限太小. 请调整 PHP 配置.',
'iTopUpdate:UI:RestoreArchive' => '您可以从归档文件 \'%1$s\' 还原应用程序',
'iTopUpdate:UI:RestoreBackup' => '您可以从 \'%1$s\' 还原数据库',
'iTopUpdate:UI:UpdateDone' => '升级成功',
'Menu:iTopUpdate' => '应用升级',
'Menu:iTopUpdate+' => '应用升级',
// Missing itop entries
'Class:ModuleInstallation/Attribute:installed' => '安装时间',
'Class:ModuleInstallation/Attribute:name' => '名称',
'Class:ModuleInstallation/Attribute:version' => '版本',
'Class:ModuleInstallation/Attribute:comment' => '备注',
]);

View File

@@ -120,6 +120,8 @@ $("#launch-fast-setup").on("click", function(e) {
var oMessage = $("#fast-setup-alert");
var oContent = $("#fast-setup-content");
oMessage.removeClass("ibo-is-hidden");
oMessage.removeClass("ibo-is-failure");
oMessage.removeClass("ibo-is-success");
oMessage.addClass("ibo-is-information");
oContent.html("{{ 'iTopUpdate:UI:SetupMessage:Compile'|dict_s }}");
@@ -134,20 +136,29 @@ $("#launch-fast-setup").on("click", function(e) {
route: "core_update_ajax.rebuild_toolkit_environment"
},
dataType: "json",
complete: function(jqXHR, textStatus) {
$("#fast-setup-wait").addClass("ibo-is-hidden");
$("#launch-fast-setup").prop("disabled", false);
fast_setup_wait.addClass("ibo-is-hidden");
},
success: function (data) {
oMessage.removeClass("ibo-is-information");
if (data.bStatus) {
oMessage.removeClass("ibo-is-failure");
oMessage.addClass("ibo-is-success");
oContent.html("{{ 'iTopUpdate:UI:SetupMessage:UpdateDone'|dict_s }}");
} else {
oMessage.removeClass("ibo-is-success");
oMessage.addClass("ibo-is-failure");
oContent.html(data.sError);
}
$("#fast-setup-wait").addClass("ibo-is-hidden");
$("#launch-fast-setup").prop("disabled", false);
fast_setup_wait.addClass("ibo-is-hidden");
},
error: function(jqXHR, textStatus, errorThrown) {
oMessage.removeClass("ibo-is-information");
oMessage.removeClass("ibo-is-success");
oMessage.addClass("ibo-is-failure");
oContent.html(textStatus + ' ' + errorThrown);
}
});

View File

@@ -20,6 +20,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
// Dictionary entries go here
));

View File

@@ -20,6 +20,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
// Dictionary entries go here
));

View File

@@ -4,43 +4,93 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//////////////////////////////////////////////////////////////////////
// Classes in 'bizmodel'
//////////////////////////////////////////////////////////////////////
//
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: FAQ
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Brick:Portal:FAQ:Menu' => 'FAQ',
'Brick:Portal:FAQ:Title' => 'FAQ',
'Brick:Portal:FAQ:Title+' => '<p>需要帮助?</p><p>查阅列表中的常见问题, 或许可以立即找到令您满意的答案.</p>',
'Class:FAQ' => 'FAQ',
'Class:FAQ+' => 'FAQ',
'Class:FAQ+' => '常见问题',
'Class:FAQ/Attribute:title' => '标题',
'Class:FAQ/Attribute:title+' => '',
'Class:FAQ/Attribute:summary' => '概要',
'Class:FAQ/Attribute:summary+' => '',
'Class:FAQ/Attribute:description' => '描述',
'Class:FAQ/Attribute:description+' => '',
'Class:FAQ/Attribute:category_id' => '类别',
'Class:FAQ/Attribute:category_id+' => '',
'Class:FAQ/Attribute:category_name' => '类别名称',
'Class:FAQ/Attribute:category_name+' => '',
'Class:FAQ/Attribute:description' => '描述',
'Class:FAQ/Attribute:description+' => '',
'Class:FAQ/Attribute:domains' => '范围',
'Class:FAQ/Attribute:error_code' => '错误编码',
'Class:FAQ/Attribute:error_code+' => '',
'Class:FAQ/Attribute:key_words' => '关键字',
'Class:FAQ/Attribute:key_words+' => '',
'Class:FAQ/Attribute:summary' => '概要',
'Class:FAQ/Attribute:summary+' => '',
'Class:FAQ/Attribute:title' => '标题',
'Class:FAQ/Attribute:title+' => '',
'Class:FAQCategory' => 'FAQ类别',
'Class:FAQCategory+' => 'FAQ类别',
'Class:FAQCategory/Attribute:faq_list' => 'FAQ',
'Class:FAQCategory/Attribute:faq_list+' => '此类别FAQ相关的所有常见问题',
'Class:FAQ/Attribute:domains' => '范围',
]);
//
// Class: FAQCategory
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:FAQCategory' => 'FAQ 类别',
'Class:FAQCategory+' => 'FAQ 类别',
'Class:FAQCategory/Attribute:name' => '名称',
'Class:FAQCategory/Attribute:name+' => '',
'Menu:FAQ' => 'FAQ',
'Menu:FAQ+' => '所有FAQ',
'Menu:FAQCategory' => 'FAQ类别',
'Menu:FAQCategory+' => '所有FAQ类别',
'Menu:Problem:Shortcuts' => '快捷方式',
'Class:FAQCategory/Attribute:faq_list' => 'FAQ',
'Class:FAQCategory/Attribute:faq_list+' => '此类别 FAQ 相关的所有常见问题',
]);
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Menu:ProblemManagement' => '问题管理',
'Menu:ProblemManagement+' => '问题管理',
'Menu:Problem:Shortcuts' => '快捷方式',
'Menu:FAQCategory' => 'FAQ 类别',
'Menu:FAQCategory+' => '所有 FAQ 类别',
'Menu:FAQ' => 'FAQ',
'Menu:FAQ+' => '所有 FAQ',
'Brick:Portal:FAQ:Menu' => 'FAQ',
'Brick:Portal:FAQ:Title' => '常见问题',
'Brick:Portal:FAQ:Title+' => '<p>需要帮助?</p><p>查阅列表中的常见问题, 或许可以立即找到令您满意的答案.</p>',
]);

View File

@@ -4,14 +4,29 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'FilesInformation:Error:CantWriteToFile' => '文件%1$s无法写入',
'FilesInformation:Error:CorruptedFile' => '文件%1$s已损坏',
'FilesInformation:Error:ListCorruptedFile' => '已损坏的文件: %1$s',
// Errors
'FilesInformation:Error:MissingFile' => '文件丢失: %1$s',
'FilesInformation:Error:CorruptedFile' => '文件 %1$s 已损坏',
'FilesInformation:Error:ListCorruptedFile' => '已损坏的文件: %1$s',
'FilesInformation:Error:CantWriteToFile' => '文件 %1$s 无法写入',
]);

View File

@@ -4,64 +4,84 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
Dict::Add('ZH CN', 'Chinese', '简体中文', [
// 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: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:MyExtensions' => '已安装的扩展',
'Menu:iTopHub:MyExtensions+' => '查看本机已安装的扩展',
'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>',
'UI:About:RemoteExtensionSource' => 'iTop Hub',
'iTopHub:AutoSubmit' => '不再询问. 下次自动进入iTop Hub.',
'iTopHub:BackupFailed' => '备份失败!',
'iTopHub:BackupFreeDiskSpaceIn' => '%1$s可用磁盘空间位于%2$s.',
'iTopHub:BackupOk' => '备份成功.',
'iTopHub:GoBtn' => '进入 iTop Hub',
'iTopHub:CloseBtn' => '关闭',
'iTopHub:GoBtn:Tooltip' => '跳到 www.itophub.io',
'iTopHub:OpenInNewWindow' => '从新窗口打开iTop Hub',
'iTopHub:AutoSubmit' => '不再询问. 下次自动进入iTop Hub.',
'UI:About:RemoteExtensionSource' => 'iTop Hub',
'iTopHub:Explanation' => '点击这个按钮您将被引导至iTop Hub.',
'iTopHub:BackupFreeDiskSpaceIn' => '%1$s 可用磁盘空间位于 %2$s.',
'iTopHub:FailedToCheckFreeDiskSpace' => '检查可用磁盘空间失败.',
'iTopHub:BackupOk' => '备份成功.',
'iTopHub:BackupFailed' => '备份失败!',
'iTopHub:Landing:Status' => '部署状态',
'iTopHub:Landing:Install' => '扩展安装进行中...',
'iTopHub:CompiledOK' => '编译成功.',
'iTopHub:ConfigurationSafelyReverted' => '安装时发生错误!<br/>系统配置将不会改变.',
'iTopHub:FailAuthent' => '认证失败.',
'iTopHub:InstalledExtensions' => '本机已安装的扩展',
'iTopHub:ExtensionCategory:Manual' => '手动安装的扩展',
'iTopHub:ExtensionCategory:Manual+' => '下列已安装的扩展是手动将文件放置到 %1$s 目录的:',
'iTopHub:ExtensionCategory:Remote' => '从 iTop Hub 安装的扩展',
'iTopHub:ExtensionCategory:Remote+' => '下列已安装的扩展是来自 iTop Hub:',
'iTopHub:NoExtensionInThisCategory' => '尚未安装扩展',
'iTopHub:NoExtensionInThisCategory+' => '浏览 iTop Hub, 去寻找符合您喜欢的扩展吧.',
'iTopHub:ExtensionNotInstalled' => '未安装',
'iTopHub:GetMoreExtensions' => '从 iTop Hub 获取扩展...',
'iTopHub:LandingWelcome' => '恭喜! 下列来自 iTop Hub 的扩展已被下载并安装到本机.',
'iTopHub:GoBackToITopBtn' => '返回'.ITOP_APPLICATION_SHORT,
'iTopHub:Uncompressing' => '扩展解压中...',
'iTopHub:InstallationWelcome' => '安装来自 iTop Hub 的扩展',
'iTopHub:DBBackupLabel' => '本机备份',
'iTopHub:DBBackupSentence' => '在升级之前,备份数据库和'.ITOP_APPLICATION_SHORT.'配置文件',
'iTopHub:DatabaseBackupProgress' => '本机备份...',
'iTopHub:DeployBtn' => '安装!',
'iTopHub:Explanation' => '点击这个按钮您将被引导至iTop Hub.',
'iTopHub:ExtensionCategory:Manual' => '手动安装的扩展',
'iTopHub:ExtensionCategory:Manual+' => '下列已安装的扩展是手动将文件放置到%1$s目录的:',
'iTopHub:ExtensionCategory:Remote' => '从iTop Hub安装的扩展',
'iTopHub:ExtensionCategory:Remote+' => '下列已安装的扩展是来自iTop Hub:',
'iTopHub:ExtensionNotInstalled' => '未安装',
'iTopHub:FailAuthent' => '认证失败.',
'iTopHub:FailedToCheckFreeDiskSpace' => '检查可用磁盘空间失败.',
'iTopHub:GetMoreExtensions' => '从iTop Hub获取扩展...',
'iTopHub:GoBackToITopBtn' => '返回'.ITOP_APPLICATION_SHORT,
'iTopHub:GoBtn' => '进入iTop Hub',
'iTopHub:GoBtn:Tooltip' => '跳到www.itophub.io',
'iTopHub:InstallationEffect:Downgrade' => '将从版本%1$s<b>降级</b>到版本%2$s.',
'iTopHub:InstallationEffect:Install' => '版本: %1$s将被安装.',
'iTopHub:DatabaseBackupProgress' => '实例备份...',
'iTopHub:InstallationEffect:Install' => '版本: %1$s 将被安装.',
'iTopHub:InstallationEffect:NoChange' => '版本: %1$s 已安装. 保持不变.',
'iTopHub:InstallationEffect:Upgrade' => '将从版本 %1$s <b>升级</b>到版本 %2$s.',
'iTopHub:InstallationEffect:Downgrade' => '将从版本 %1$s <b>降级</b>到版本 %2$s.',
'iTopHub:InstallationProgress:DatabaseBackup' => ITOP_APPLICATION_SHORT.'实例备份...',
'iTopHub:InstallationProgress:ExtensionsInstallation' => '安装扩展',
'iTopHub:InstallationEffect:MissingDependencies' => '扩展无法安装, 因为未知的依赖.',
'iTopHub:InstallationEffect:MissingDependencies_Details' => '此扩展依赖模块: %1$s',
'iTopHub:InstallationEffect:NoChange' => '版本: %1$s已安装. 保持不变.',
'iTopHub:InstallationEffect:Upgrade' => '将从版本%1$s<b>升级</b>到版本%2$s.',
'iTopHub:InstallationProgress:DatabaseBackup' => ITOP_APPLICATION_SHORT.'本机备份...',
'iTopHub:InstallationProgress:ExtensionsInstallation' => '安装扩展',
'iTopHub:InstallationProgress:InstallationSuccessful' => '安装成功!',
'iTopHub:InstallationStatus:Installed_Version' => '%1$s 版本: %2$s.',
'iTopHub:InstallationStatus:Installed' => '已安装',
'iTopHub:InstallationStatus:Installed_Version' => '%1$s版本: %2$s.',
'iTopHub:InstallationStatus:Version_NotInstalled' => '版本%1$s<b>未</b>安装.',
'iTopHub:InstallationWelcome' => '安装来自iTop Hub的扩展',
'iTopHub:InstalledExtensions' => '本机已安装的扩展',
'iTopHub:Landing:Install' => '扩展安装进行中...',
'iTopHub:Landing:Status' => '安装状态',
'iTopHub:LandingWelcome' => '恭喜! 下列来自iTop Hub的扩展已被下载并安装到本机.',
'iTopHub:NoExtensionInThisCategory' => '尚未安装扩展',
'iTopHub:NoExtensionInThisCategory+' => '浏览iTop Hub, 去寻找符合您喜欢的扩展吧.',
'iTopHub:OpenInNewWindow' => '从新窗口打开iTop Hub',
'iTopHub:Uncompressing' => '扩展解压中...',
'iTopHub:InstallationStatus:Version_NotInstalled' => '版本 %1$s <b>未被</b> 安装.',
]);

View File

@@ -4,70 +4,93 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Menu:IncidentManagement' => '事件管理',
'Menu:IncidentManagement+' => '事件管理',
'Menu:Incident:Overview' => '概况',
'Menu:Incident:Overview+' => '概况',
'Menu:NewIncident' => '新建事件',
'Menu:NewIncident+' => '新建事件工单',
'Menu:SearchIncidents' => '搜索事件',
'Menu:SearchIncidents+' => '搜索事件',
'Menu:Incident:Shortcuts' => '快捷方式',
'Menu:Incident:Shortcuts+' => '',
'Menu:Incident:MyIncidents' => '分配给我的事件',
'Menu:Incident:MyIncidents+' => '分配给我的事件',
'Menu:Incident:EscalatedIncidents' => '已升级的事件',
'Menu:Incident:EscalatedIncidents+' => '已升级的事件',
'Menu:Incident:OpenIncidents' => '所有打开的事件',
'Menu:Incident:OpenIncidents+' => '所有打开的事件',
'UI-IncidentManagementOverview-IncidentByPriority-last-14-days' => '最近两周的事件 (按优先级)',
'UI-IncidentManagementOverview-Last-14-days' => '最近两周的事件 (按数量)',
'UI-IncidentManagementOverview-OpenIncidentByStatus' => '打开的事件 (按状态)',
'UI-IncidentManagementOverview-OpenIncidentByAgent' => '打开的事件 (按办理人)',
'UI-IncidentManagementOverview-OpenIncidentByCustomer' => '打开的事件 (按客户)',
]);
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: Incident
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:Incident' => '事件',
'Class:Incident+' => '',
'Class:Incident/Attribute:assignment_date' => '分配日期',
'Class:Incident/Attribute:assignment_date+' => '',
'Class:Incident/Attribute:child_incidents_list' => '子事件',
'Class:Incident/Attribute:child_incidents_list+' => '此事件相关的所有衍生事件',
'Class:Incident/Attribute:cumulatedpending' => '累计待定',
'Class:Incident/Attribute:cumulatedpending+' => '',
'Class:Incident/Attribute:escalation_flag' => '是否升级',
'Class:Incident/Attribute:escalation_flag+' => '',
'Class:Incident/Attribute:escalation_flag/Value:no' => '',
'Class:Incident/Attribute:escalation_flag/Value:no+' => '',
'Class:Incident/Attribute:escalation_flag/Value:yes' => '',
'Class:Incident/Attribute:escalation_flag/Value:yes+' => '',
'Class:Incident/Attribute:escalation_reason' => '升级原因',
'Class:Incident/Attribute:escalation_reason+' => '',
'Class:Incident/Attribute:status' => '状态',
'Class:Incident/Attribute:status+' => '',
'Class:Incident/Attribute:status/Value:new' => '新建',
'Class:Incident/Attribute:status/Value:new+' => '',
'Class:Incident/Attribute:status/Value:escalated_tto' => '已升级TTO',
'Class:Incident/Attribute:status/Value:escalated_tto+' => '',
'Class:Incident/Attribute:status/Value:assigned' => '已分配',
'Class:Incident/Attribute:status/Value:assigned+' => '',
'Class:Incident/Attribute:status/Value:escalated_ttr' => '已升级TTR',
'Class:Incident/Attribute:status/Value:escalated_ttr+' => '',
'Class:Incident/Attribute:status/Value:waiting_for_approval' => '等待批准',
'Class:Incident/Attribute:status/Value:waiting_for_approval+' => '',
'Class:Incident/Attribute:status/Value:pending' => '待定',
'Class:Incident/Attribute:status/Value:pending+' => '',
'Class:Incident/Attribute:status/Value:resolved' => '已解决',
'Class:Incident/Attribute:status/Value:resolved+' => '',
'Class:Incident/Attribute:status/Value:closed' => '已关闭',
'Class:Incident/Attribute:status/Value:closed+' => '',
'Class:Incident/Attribute:impact' => '影响范围',
'Class:Incident/Attribute:impact+' => '',
'Class:Incident/Attribute:impact+' => '事件的影响范围,多少用户受影响',
'Class:Incident/Attribute:impact/Value:1' => '部门',
'Class:Incident/Attribute:impact/Value:1+' => '',
'Class:Incident/Attribute:impact/Value:2' => '服务',
'Class:Incident/Attribute:impact/Value:2+' => '',
'Class:Incident/Attribute:impact/Value:3' => '个体',
'Class:Incident/Attribute:impact/Value:3+' => '',
'Class:Incident/Attribute:last_pending_date' => '最近待定日期',
'Class:Incident/Attribute:last_pending_date+' => '',
'Class:Incident/Attribute:origin' => '来源',
'Class:Incident/Attribute:origin+' => '',
'Class:Incident/Attribute:origin/Value:chat' => '聊天工具',
'Class:Incident/Attribute:origin/Value:chat+' => '创建于聊天工具沟通后的事件',
'Class:Incident/Attribute:origin/Value:in_person' => '当面',
'Class:Incident/Attribute:origin/Value:in_person+' => '创建于当面沟通后的事件',
'Class:Incident/Attribute:origin/Value:mail' => '邮件',
'Class:Incident/Attribute:origin/Value:mail+' => '邮件',
'Class:Incident/Attribute:origin/Value:monitoring' => '监控',
'Class:Incident/Attribute:origin/Value:monitoring+' => '监控',
'Class:Incident/Attribute:origin/Value:phone' => '电话',
'Class:Incident/Attribute:origin/Value:phone+' => '电话',
'Class:Incident/Attribute:origin/Value:portal' => '门户',
'Class:Incident/Attribute:origin/Value:portal+' => '门户',
'Class:Incident/Attribute:parent_change_id' => '父级变更',
'Class:Incident/Attribute:parent_change_id+' => '',
'Class:Incident/Attribute:parent_change_ref' => '变更编号',
'Class:Incident/Attribute:parent_change_ref+' => '',
'Class:Incident/Attribute:parent_incident_id' => '父级事件',
'Class:Incident/Attribute:parent_incident_id+' => '',
'Class:Incident/Attribute:parent_incident_id_friendlyname' => '父级事件名称',
'Class:Incident/Attribute:parent_incident_id_friendlyname+' => '',
'Class:Incident/Attribute:parent_incident_ref' => '事件编号',
'Class:Incident/Attribute:parent_incident_ref+' => '',
'Class:Incident/Attribute:parent_problem_id' => '父级问题',
'Class:Incident/Attribute:parent_problem_id+' => '~~',
'Class:Incident/Attribute:parent_problem_ref' => '父级问题编号',
'Class:Incident/Attribute:parent_problem_ref+' => '~~',
'Class:Incident/Attribute:pending_reason' => '待定原因',
'Class:Incident/Attribute:pending_reason+' => '',
'Class:Incident/Attribute:priority' => '优先级',
'Class:Incident/Attribute:priority+' => '',
'Class:Incident/Attribute:priority+' => '哪个工单应该优先处理',
'Class:Incident/Attribute:priority/Value:1' => '紧急',
'Class:Incident/Attribute:priority/Value:1+' => '紧急',
'Class:Incident/Attribute:priority/Value:2' => '高',
@@ -76,10 +99,72 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:Incident/Attribute:priority/Value:3+' => '中',
'Class:Incident/Attribute:priority/Value:4' => '低',
'Class:Incident/Attribute:priority/Value:4+' => '低',
'Class:Incident/Attribute:public_log' => '评论',
'Class:Incident/Attribute:public_log+' => '',
'Class:Incident/Attribute:related_request_list' => '相关需求',
'Class:Incident/Attribute:related_request_list+' => '此事件相关的所有需求',
'Class:Incident/Attribute:urgency' => '紧急度',
'Class:Incident/Attribute:urgency+' => '问题应该多快解决',
'Class:Incident/Attribute:urgency/Value:1' => '紧急',
'Class:Incident/Attribute:urgency/Value:1+' => '紧急',
'Class:Incident/Attribute:urgency/Value:2' => '高',
'Class:Incident/Attribute:urgency/Value:2+' => '高',
'Class:Incident/Attribute:urgency/Value:3' => '中',
'Class:Incident/Attribute:urgency/Value:3+' => '中',
'Class:Incident/Attribute:urgency/Value:4' => '低',
'Class:Incident/Attribute:urgency/Value:4+' => '低',
'Class:Incident/Attribute:origin' => '来源',
'Class:Incident/Attribute:origin+' => '事件工单由谁发起或触发的',
'Class:Incident/Attribute:origin/Value:in_person' => '当面',
'Class:Incident/Attribute:origin/Value:in_person+' => '创建于当面沟通后的事件',
'Class:Incident/Attribute:origin/Value:chat' => '聊天工具',
'Class:Incident/Attribute:origin/Value:chat+' => '创建于聊天工具沟通后的事件',
'Class:Incident/Attribute:origin/Value:mail' => '邮件',
'Class:Incident/Attribute:origin/Value:mail+' => '邮件',
'Class:Incident/Attribute:origin/Value:monitoring' => '监控',
'Class:Incident/Attribute:origin/Value:monitoring+' => '监控',
'Class:Incident/Attribute:origin/Value:phone' => '电话',
'Class:Incident/Attribute:origin/Value:phone+' => '电话',
'Class:Incident/Attribute:origin/Value:portal' => '门户',
'Class:Incident/Attribute:origin/Value:portal+' => '门户',
'Class:Incident/Attribute:service_id' => '服务',
'Class:Incident/Attribute:service_id+' => '',
'Class:Incident/Attribute:service_name' => '服务名称',
'Class:Incident/Attribute:service_name+' => '',
'Class:Incident/Attribute:servicesubcategory_id' => '子服务',
'Class:Incident/Attribute:servicesubcategory_id+' => '',
'Class:Incident/Attribute:servicesubcategory_name' => '子服务名称',
'Class:Incident/Attribute:servicesubcategory_name+' => '',
'Class:Incident/Attribute:escalation_flag' => '是否升级',
'Class:Incident/Attribute:escalation_flag+' => '',
'Class:Incident/Attribute:escalation_flag/Value:no' => '否',
'Class:Incident/Attribute:escalation_flag/Value:no+' => '否',
'Class:Incident/Attribute:escalation_flag/Value:yes' => '是',
'Class:Incident/Attribute:escalation_flag/Value:yes+' => '是',
'Class:Incident/Attribute:escalation_reason' => '升级原因',
'Class:Incident/Attribute:escalation_reason+' => '',
'Class:Incident/Attribute:assignment_date' => '分配日期',
'Class:Incident/Attribute:assignment_date+' => '',
'Class:Incident/Attribute:resolution_date' => '解决日期',
'Class:Incident/Attribute:resolution_date+' => '',
'Class:Incident/Attribute:last_pending_date' => '最近待定日期',
'Class:Incident/Attribute:last_pending_date+' => '',
'Class:Incident/Attribute:cumulatedpending' => '累计待定',
'Class:Incident/Attribute:cumulatedpending+' => '',
'Class:Incident/Attribute:tto' => 'TTO',
'Class:Incident/Attribute:tto+' => '响应时间',
'Class:Incident/Attribute:ttr' => 'TTR',
'Class:Incident/Attribute:ttr+' => '解决时限',
'Class:Incident/Attribute:tto_escalation_deadline' => 'TTO截止日期',
'Class:Incident/Attribute:tto_escalation_deadline+' => '',
'Class:Incident/Attribute:sla_tto_passed' => 'SLA TTO合格',
'Class:Incident/Attribute:sla_tto_passed+' => '',
'Class:Incident/Attribute:sla_tto_over' => 'SLA TTO超时',
'Class:Incident/Attribute:sla_tto_over+' => '',
'Class:Incident/Attribute:ttr_escalation_deadline' => 'TTR截止日期',
'Class:Incident/Attribute:ttr_escalation_deadline+' => '',
'Class:Incident/Attribute:sla_ttr_passed' => 'SLA TTR合格',
'Class:Incident/Attribute:sla_ttr_passed+' => '',
'Class:Incident/Attribute:sla_ttr_over' => 'SLA TTR超时',
'Class:Incident/Attribute:sla_ttr_over+' => '',
'Class:Incident/Attribute:time_spent' => '耗时',
'Class:Incident/Attribute:time_spent+' => '',
'Class:Incident/Attribute:resolution_code' => '解决方式',
'Class:Incident/Attribute:resolution_code+' => '',
'Class:Incident/Attribute:resolution_code/Value:assistance' => '外部支持',
@@ -96,66 +181,28 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:Incident/Attribute:resolution_code/Value:system update+' => '系统更新',
'Class:Incident/Attribute:resolution_code/Value:training' => '培训',
'Class:Incident/Attribute:resolution_code/Value:training+' => '培训',
'Class:Incident/Attribute:resolution_date' => '解决日期',
'Class:Incident/Attribute:resolution_date+' => '',
'Class:Incident/Attribute:service_id' => '服务',
'Class:Incident/Attribute:service_id+' => '',
'Class:Incident/Attribute:service_name' => '服务名称',
'Class:Incident/Attribute:service_name+' => '',
'Class:Incident/Attribute:servicesubcategory_id' => '子服务',
'Class:Incident/Attribute:servicesubcategory_id+' => '',
'Class:Incident/Attribute:servicesubcategory_name' => '子服务名称',
'Class:Incident/Attribute:servicesubcategory_name+' => '',
'Class:Incident/Attribute:sla_tto_over' => 'SLA TTO超时',
'Class:Incident/Attribute:sla_tto_over+' => '',
'Class:Incident/Attribute:sla_tto_passed' => 'SLA TTO合格',
'Class:Incident/Attribute:sla_tto_passed+' => '',
'Class:Incident/Attribute:sla_ttr_over' => 'SLA TTR超时',
'Class:Incident/Attribute:sla_ttr_over+' => '',
'Class:Incident/Attribute:sla_ttr_passed' => 'SLA TTR合格',
'Class:Incident/Attribute:sla_ttr_passed+' => '',
'Class:Incident/Attribute:solution' => '解决方案',
'Class:Incident/Attribute:solution+' => '',
'Class:Incident/Attribute:status' => '状态',
'Class:Incident/Attribute:status+' => '',
'Class:Incident/Attribute:status/Value:assigned' => '已分配',
'Class:Incident/Attribute:status/Value:assigned+' => '',
'Class:Incident/Attribute:status/Value:closed' => '已关闭',
'Class:Incident/Attribute:status/Value:closed+' => '',
'Class:Incident/Attribute:status/Value:escalated_tto' => '已升级TTO',
'Class:Incident/Attribute:status/Value:escalated_tto+' => '',
'Class:Incident/Attribute:status/Value:escalated_ttr' => '已升级TTR',
'Class:Incident/Attribute:status/Value:escalated_ttr+' => '',
'Class:Incident/Attribute:status/Value:new' => '新建',
'Class:Incident/Attribute:status/Value:new+' => '',
'Class:Incident/Attribute:status/Value:pending' => '待定',
'Class:Incident/Attribute:status/Value:pending+' => '',
'Class:Incident/Attribute:status/Value:resolved' => '已解决',
'Class:Incident/Attribute:status/Value:resolved+' => '',
'Class:Incident/Attribute:status/Value:waiting_for_approval' => '等待批准',
'Class:Incident/Attribute:status/Value:waiting_for_approval+' => '',
'Class:Incident/Attribute:time_spent' => '耗时',
'Class:Incident/Attribute:time_spent+' => '',
'Class:Incident/Attribute:tto' => 'TTO',
'Class:Incident/Attribute:tto+' => '响应时间',
'Class:Incident/Attribute:tto_escalation_deadline' => 'TTO截止日期',
'Class:Incident/Attribute:tto_escalation_deadline+' => '',
'Class:Incident/Attribute:ttr' => 'TTR',
'Class:Incident/Attribute:ttr+' => '解决时限',
'Class:Incident/Attribute:ttr_escalation_deadline' => 'TTR截止日期',
'Class:Incident/Attribute:ttr_escalation_deadline+' => '',
'Class:Incident/Attribute:urgency' => '紧急度',
'Class:Incident/Attribute:urgency+' => '',
'Class:Incident/Attribute:urgency/Value:1' => '紧急',
'Class:Incident/Attribute:urgency/Value:1+' => '紧急',
'Class:Incident/Attribute:urgency/Value:2' => '高',
'Class:Incident/Attribute:urgency/Value:2+' => '高',
'Class:Incident/Attribute:urgency/Value:3' => '中',
'Class:Incident/Attribute:urgency/Value:3+' => '中',
'Class:Incident/Attribute:urgency/Value:4' => '低',
'Class:Incident/Attribute:urgency/Value:4+' => '低',
'Class:Incident/Attribute:user_comment' => '用户评论',
'Class:Incident/Attribute:user_comment+' => '',
'Class:Incident/Attribute:pending_reason' => '待定原因',
'Class:Incident/Attribute:pending_reason+' => '',
'Class:Incident/Attribute:parent_incident_id' => '父级事件',
'Class:Incident/Attribute:parent_incident_id+' => '',
'Class:Incident/Attribute:parent_incident_ref' => '事件编号',
'Class:Incident/Attribute:parent_incident_ref+' => '',
'Class:Incident/Attribute:parent_change_id' => '父级变更',
'Class:Incident/Attribute:parent_change_id+' => '',
'Class:Incident/Attribute:parent_change_ref' => '变更编号',
'Class:Incident/Attribute:parent_change_ref+' => '',
'Class:Incident/Attribute:parent_problem_id' => '父级问题',
'Class:Incident/Attribute:parent_problem_id+' => '~~',
'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:child_incidents_list' => '子事件',
'Class:Incident/Attribute:child_incidents_list+' => '此事件相关的所有衍生事件',
'Class:Incident/Attribute:public_log' => '评论',
'Class:Incident/Attribute:public_log+' => '',
'Class:Incident/Attribute:user_satisfaction' => '用户满意度',
'Class:Incident/Attribute:user_satisfaction+' => '',
'Class:Incident/Attribute:user_satisfaction/Value:1' => '非常满意',
@@ -166,47 +213,31 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:Incident/Attribute:user_satisfaction/Value:3+' => '不满意',
'Class:Incident/Attribute:user_satisfaction/Value:4' => '非常不满意',
'Class:Incident/Attribute:user_satisfaction/Value:4+' => '非常不满意',
'Class:Incident/Error:CannotAssignParentIncidentIdToSelf' => '无法分配父级事件给自己',
'Class:Incident/Method:ResolveChildTickets' => '解决子工单',
'Class:Incident/Method:ResolveChildTickets+' => '递归解决子工单 (自动解决), 并调整相关字段与父级工单保持一致: 服务, 团队, 办理人, 解决方案',
'Class:Incident/Attribute:user_comment' => '用户评论',
'Class:Incident/Attribute:user_comment+' => '',
'Class:Incident/Attribute:parent_incident_id_friendlyname' => '父级事件名称',
'Class:Incident/Attribute:parent_incident_id_friendlyname+' => '',
'Class:Incident/Stimulus:ev_assign' => '分配',
'Class:Incident/Stimulus:ev_assign+' => '',
'Class:Incident/Stimulus:ev_autoclose' => '自动关闭',
'Class:Incident/Stimulus:ev_autoclose+' => '',
'Class:Incident/Stimulus:ev_autoresolve' => '自动解决',
'Class:Incident/Stimulus:ev_autoresolve+' => '',
'Class:Incident/Stimulus:ev_close' => '关闭',
'Class:Incident/Stimulus:ev_close+' => '',
'Class:Incident/Stimulus:ev_pending' => '待定',
'Class:Incident/Stimulus:ev_pending+' => '',
'Class:Incident/Stimulus:ev_reassign' => '重新分配',
'Class:Incident/Stimulus:ev_reassign+' => '',
'Class:Incident/Stimulus:ev_reopen' => '重新打开',
'Class:Incident/Stimulus:ev_reopen+' => '',
'Class:Incident/Stimulus:ev_resolve' => '标记为已解决',
'Class:Incident/Stimulus:ev_resolve+' => '',
'Class:Incident/Stimulus:ev_pending' => '待定',
'Class:Incident/Stimulus:ev_pending+' => '',
'Class:Incident/Stimulus:ev_timeout' => '超时',
'Class:Incident/Stimulus:ev_timeout+' => '',
'Menu:Incident:EscalatedIncidents' => '已升级的事件',
'Menu:Incident:EscalatedIncidents+' => '已升级的事件',
'Menu:Incident:MyIncidents' => '分配给我的事件',
'Menu:Incident:MyIncidents+' => '分配给我的事件',
'Menu:Incident:OpenIncidents' => '所有打开的事件',
'Menu:Incident:OpenIncidents+' => '所有打开的事件',
'Menu:Incident:Overview' => '概况',
'Menu:Incident:Overview+' => '概况',
'Menu:Incident:Shortcuts' => '快捷方式',
'Menu:Incident:Shortcuts+' => '',
'Menu:IncidentManagement' => '事件管理',
'Menu:IncidentManagement+' => '事件管理',
'Menu:NewIncident' => '新建事件',
'Menu:NewIncident+' => '新建事件',
'Menu:SearchIncidents' => '搜索事件',
'Menu:SearchIncidents+' => '搜索事件',
'Class:Incident/Stimulus:ev_autoresolve' => '自动解决',
'Class:Incident/Stimulus:ev_autoresolve+' => '',
'Class:Incident/Stimulus:ev_autoclose' => '自动关闭',
'Class:Incident/Stimulus:ev_autoclose+' => '',
'Class:Incident/Stimulus:ev_resolve' => '标记为已解决',
'Class:Incident/Stimulus:ev_resolve+' => '',
'Class:Incident/Stimulus:ev_close' => '关闭',
'Class:Incident/Stimulus:ev_close+' => '',
'Class:Incident/Stimulus:ev_reopen' => '重新打开',
'Class:Incident/Stimulus:ev_reopen+' => '',
'Class:Incident/Error:CannotAssignParentIncidentIdToSelf' => '无法分配父级事件给自己',
'Class:Incident/Method:ResolveChildTickets' => '解决子工单',
'Class:Incident/Method:ResolveChildTickets+' => '递归解决子工单 (自动解决), 并调整相关字段与父级工单保持一致: 服务, 团队, 办理人, 解决方案',
'Tickets:Related:OpenIncidents' => '打开的事件',
'UI-IncidentManagementOverview-IncidentByPriority-last-14-days' => '最近两周的事件 (按优先级)',
'UI-IncidentManagementOverview-Last-14-days' => '最近两周的事件 (按数量)',
'UI-IncidentManagementOverview-OpenIncidentByAgent' => '打开的事件 (按办理人)',
'UI-IncidentManagementOverview-OpenIncidentByCustomer' => '打开的事件 (按客户)',
'UI-IncidentManagementOverview-OpenIncidentByStatus' => '打开的事件 (按状态)',
]);

View File

@@ -4,20 +4,75 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//////////////////////////////////////////////////////////////////////
// Classes in 'bizmodel'
//////////////////////////////////////////////////////////////////////
//
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: KnownError
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:KnownError' => '已知错误',
'Class:KnownError+' => '记录一个已知错误',
'Class:KnownError/Attribute:ci_list' => '配置项',
'Class:KnownError/Attribute:ci_list+' => '此已知错误相关的所有配置项',
'Class:KnownError/Attribute:name' => '名称',
'Class:KnownError/Attribute:name+' => '',
'Class:KnownError/Attribute:org_id' => '客户',
'Class:KnownError/Attribute:org_id+' => '',
'Class:KnownError/Attribute:cust_name' => '客户名称',
'Class:KnownError/Attribute:cust_name+' => '',
'Class:KnownError/Attribute:document_list' => '文档',
'Class:KnownError/Attribute:document_list+' => '此已知错误相关的所有文档',
'Class:KnownError/Attribute:problem_id' => '相关问题',
'Class:KnownError/Attribute:problem_id+' => '',
'Class:KnownError/Attribute:problem_ref' => '问题编号',
'Class:KnownError/Attribute:problem_ref+' => '',
'Class:KnownError/Attribute:symptom' => '现象',
'Class:KnownError/Attribute:symptom+' => '',
'Class:KnownError/Attribute:root_cause' => '问题根源',
'Class:KnownError/Attribute:root_cause+' => '',
'Class:KnownError/Attribute:workaround' => '解决过程',
'Class:KnownError/Attribute:workaround+' => '',
'Class:KnownError/Attribute:solution' => '解决方案',
'Class:KnownError/Attribute:solution+' => '',
'Class:KnownError/Attribute:error_code' => '错误编码',
'Class:KnownError/Attribute:error_code+' => '',
'Class:KnownError/Attribute:domain' => '类型',
'Class:KnownError/Attribute:domain+' => '',
'Class:KnownError/Attribute:domain/Value:Application' => '应用',
@@ -28,32 +83,46 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:KnownError/Attribute:domain/Value:Network+' => '网络',
'Class:KnownError/Attribute:domain/Value:Server' => '服务器',
'Class:KnownError/Attribute:domain/Value:Server+' => '服务器',
'Class:KnownError/Attribute:error_code' => '错误编码',
'Class:KnownError/Attribute:error_code+' => '',
'Class:KnownError/Attribute:model' => '型号',
'Class:KnownError/Attribute:model+' => '',
'Class:KnownError/Attribute:name' => '名称',
'Class:KnownError/Attribute:name+' => '',
'Class:KnownError/Attribute:org_id' => '客户',
'Class:KnownError/Attribute:org_id+' => '',
'Class:KnownError/Attribute:problem_id' => '相关问题',
'Class:KnownError/Attribute:problem_id+' => '',
'Class:KnownError/Attribute:problem_ref' => '问题编号',
'Class:KnownError/Attribute:problem_ref+' => '',
'Class:KnownError/Attribute:root_cause' => '问题根源',
'Class:KnownError/Attribute:root_cause+' => '',
'Class:KnownError/Attribute:solution' => '解决方案',
'Class:KnownError/Attribute:solution+' => '',
'Class:KnownError/Attribute:symptom' => '现象',
'Class:KnownError/Attribute:symptom+' => '',
'Class:KnownError/Attribute:vendor' => '厂商',
'Class:KnownError/Attribute:vendor+' => '',
'Class:KnownError/Attribute:model' => '型号',
'Class:KnownError/Attribute:model+' => '',
'Class:KnownError/Attribute:version' => '版本',
'Class:KnownError/Attribute:version+' => '',
'Class:KnownError/Attribute:workaround' => '解决过程',
'Class:KnownError/Attribute:workaround+' => '',
'Class:KnownError/Attribute:ci_list' => '配置项',
'Class:KnownError/Attribute:ci_list+' => '此已知错误相关的所有配置项',
'Class:KnownError/Attribute:document_list' => '文档',
'Class:KnownError/Attribute:document_list+' => '此已知错误相关的所有文档',
]);
//
// Class: lnkErrorToFunctionalCI
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:lnkErrorToFunctionalCI' => '关联已知问题/功能配置项',
'Class:lnkErrorToFunctionalCI+' => '已知问题和功能配置项之间的关联',
'Class:lnkErrorToFunctionalCI/Name' => '%1$s / %2$s',
'Class:lnkErrorToFunctionalCI/Attribute:functionalci_id' => '配置项',
'Class:lnkErrorToFunctionalCI/Attribute:functionalci_id+' => '',
'Class:lnkErrorToFunctionalCI/Attribute:functionalci_name' => '配置项名称',
'Class:lnkErrorToFunctionalCI/Attribute:functionalci_name+' => '',
'Class:lnkErrorToFunctionalCI/Attribute:error_id' => '已知问题',
'Class:lnkErrorToFunctionalCI/Attribute:error_id+' => '',
'Class:lnkErrorToFunctionalCI/Attribute:error_name' => '已知问题名称',
'Class:lnkErrorToFunctionalCI/Attribute:error_name+' => '',
'Class:lnkErrorToFunctionalCI/Attribute:reason' => '原因',
'Class:lnkErrorToFunctionalCI/Attribute:reason+' => '',
]);
//
// Class: lnkDocumentToError
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:lnkDocumentToError' => '关联文档/已知问题',
'Class:lnkDocumentToError+' => '文档和已知问题之间的关联',
'Class:lnkDocumentToError/Name' => '%1$s / %2$s',
'Class:lnkDocumentToError/Attribute:document_id' => '文档',
'Class:lnkDocumentToError/Attribute:document_id+' => '',
'Class:lnkDocumentToError/Attribute:document_name' => '文档名称',
@@ -64,27 +133,16 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:lnkDocumentToError/Attribute:error_name+' => '',
'Class:lnkDocumentToError/Attribute:link_type' => '关联类型',
'Class:lnkDocumentToError/Attribute:link_type+' => '',
'Class:lnkDocumentToError/Name' => '%1$s / %2$s~~',
'Class:lnkErrorToFunctionalCI' => '关联已知问题/功能配置项',
'Class:lnkErrorToFunctionalCI+' => '已知问题和功能配置项之间的关联',
'Class:lnkErrorToFunctionalCI/Attribute:error_id' => '已知问题',
'Class:lnkErrorToFunctionalCI/Attribute:error_id+' => '',
'Class:lnkErrorToFunctionalCI/Attribute:error_name' => '已知问题名称',
'Class:lnkErrorToFunctionalCI/Attribute:error_name+' => '',
'Class:lnkErrorToFunctionalCI/Attribute:functionalci_id' => '配置项',
'Class:lnkErrorToFunctionalCI/Attribute:functionalci_id+' => '',
'Class:lnkErrorToFunctionalCI/Attribute:functionalci_name' => '配置项名称',
'Class:lnkErrorToFunctionalCI/Attribute:functionalci_name+' => '',
'Class:lnkErrorToFunctionalCI/Attribute:reason' => '原因',
'Class:lnkErrorToFunctionalCI/Attribute:reason+' => '',
'Class:lnkErrorToFunctionalCI/Name' => '%1$s / %2$s~~',
'Menu:NewError' => '新建已知问题',
'Menu:NewError+' => '新建已知问题',
'Menu:Problem:KnownErrors' => '所有已知错误',
'Menu:Problem:KnownErrors+' => '所有已知错误',
'Menu:Problem:Shortcuts' => '快捷方式',
]);
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Menu:ProblemManagement' => '问题管理',
'Menu:ProblemManagement+' => '问题管理',
'Menu:Problem:Shortcuts' => '快捷方式',
'Menu:NewError' => '新建已知问题',
'Menu:NewError+' => '新建已知问题',
'Menu:SearchError' => '搜索已知问题',
'Menu:SearchError+' => '搜索已知问题',
'Menu:Problem:KnownErrors' => '所有已知错误',
'Menu:Problem:KnownErrors+' => '所有已知错误',
]);

View File

@@ -952,5 +952,22 @@ HTML
</classes>
</group>
</groups>
<profiles>
<profile id="117" _delta="if_exists">
<!-- SuperUser -->
<groups>
<group id="OauthConnection">
<actions>
<action id="action:read">allow</action>
<action id="action:write">allow</action>
<action id="action:delete">allow</action>
<action id="action:bulk read">allow</action>
<action id="action:bulk write">allow</action>
<action id="action:bulk delete">allow</action>
</actions>
</group>
</groups>
</profile>
</profiles>
</user_rights>
</itop_design>

View File

@@ -10,7 +10,7 @@
*
*/
Dict::Add('CS CZ', 'Czech', 'Čeština', [
'Class:OAuthClient' => 'OAuth Client~~',
'Class:OAuthClient' => 'OAuth Mail Access~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => 'A long string of characters provided by your OAuth2 provider~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
@@ -40,7 +40,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure' => 'OAuth Mail Access for Microsoft Azure~~',
'Class:OAuthClientAzure/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientAzure/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientAzure/Attribute:scope' => 'Scope~~',
@@ -62,7 +62,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple' => 'Simple~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple+' => '~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle' => 'OAuth Mail Access for Google~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientGoogle/Attribute:scope' => 'Scope~~',
@@ -84,7 +84,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:GenerateTokens' => 'Generate access token...~~',
'Menu:OAuthClient' => 'OAuth client~~',
'Menu:OAuthClient' => 'OAuth Mail Access~~',
'Menu:OAuthClient+' => '~~',
'Menu:RegenerateTokens' => 'Regenerate access token...~~',
'OAuthClient:Name/UseForSMTPMustBeUnique' => 'The combination Login (%1$s) and Use for SMTP (%2$s) has already been used for OAuth Client~~',

View File

@@ -10,7 +10,7 @@
*
*/
Dict::Add('DA DA', 'Danish', 'Dansk', [
'Class:OAuthClient' => 'OAuth Client~~',
'Class:OAuthClient' => 'OAuth Mail Access~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => 'A long string of characters provided by your OAuth2 provider~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
@@ -40,7 +40,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure' => 'OAuth Mail Access for Microsoft Azure~~',
'Class:OAuthClientAzure/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientAzure/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientAzure/Attribute:scope' => 'Scope~~',
@@ -62,7 +62,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple' => 'Simple~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple+' => '~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle' => 'OAuth Mail Access for Google~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientGoogle/Attribute:scope' => 'Scope~~',
@@ -84,7 +84,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:GenerateTokens' => 'Generate access token...~~',
'Menu:OAuthClient' => 'OAuth client~~',
'Menu:OAuthClient' => 'OAuth Mail Access~~',
'Menu:OAuthClient+' => '~~',
'Menu:RegenerateTokens' => 'Regenerate access token...~~',
'OAuthClient:Name/UseForSMTPMustBeUnique' => 'The combination Login (%1$s) and Use for SMTP (%2$s) has already been used for OAuth Client~~',

View File

@@ -4,13 +4,13 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*
*/
/**
*
*/
Dict::Add('DE DE', 'German', 'Deutsch', [
'Class:OAuthClient' => 'OAuth-Client',
'Class:OAuthClient' => 'Mailpostfach-OAuth-Client',
'Class:OAuthClient/Attribute:client_id' => 'Client ID',
'Class:OAuthClient/Attribute:client_id+' => 'Eine lange Zeichenfolge, die durch den oAuth2-Provider bereitgestellt wird',
'Class:OAuthClient/Attribute:client_secret' => 'Client Secret',
@@ -40,7 +40,7 @@ Löschen Sie das Feld, um den Standardwert neu zu berechnen.',
'Class:OAuthClient/Attribute:token+' => '',
'Class:OAuthClient/Attribute:token_expiration' => 'Zugriffstoken Ablaufszeitpunkt',
'Class:OAuthClient/Attribute:token_expiration+' => '',
'Class:OAuthClientAzure' => 'OAuth-Client für Microsoft Azure',
'Class:OAuthClientAzure' => 'Mailpostfach-OAuth-Client für Microsoft Azure',
'Class:OAuthClientAzure/Attribute:advanced_scope' => 'Erweiterter Scope',
'Class:OAuthClientAzure/Attribute:advanced_scope+' => 'Sobald Sie hier etwas eingeben, hat es Vorrang vor der Auswahl im Feld "Scope", die dann ignoriert wird.',
'Class:OAuthClientAzure/Attribute:scope' => 'Scope',
@@ -62,7 +62,7 @@ Löschen Sie das Feld, um den Standardwert neu zu berechnen.',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple' => 'Einfach',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple+' => '',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)',
'Class:OAuthClientGoogle' => 'OAuth-Client für Google',
'Class:OAuthClientGoogle' => 'Mailpostfach-OAuth-Client für Google',
'Class:OAuthClientGoogle/Attribute:advanced_scope' => 'Erweiterter Scope',
'Class:OAuthClientGoogle/Attribute:advanced_scope+' => 'Sobald Sie hier etwas eingeben, hat es Vorrang vor der Auswahl im Feld "Scope", die dann ignoriert wird.',
'Class:OAuthClientGoogle/Attribute:scope' => 'Scope',
@@ -84,7 +84,7 @@ Löschen Sie das Feld, um den Standardwert neu zu berechnen.',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)',
'Menu:CreateMailbox' => 'Mailpostfach erstellen...',
'Menu:GenerateTokens' => 'Zugriffstoken generieren...',
'Menu:OAuthClient' => 'OAuth-Client',
'Menu:OAuthClient' => 'Mailpostfach-OAuth-Client',
'Menu:OAuthClient+' => '',
'Menu:RegenerateTokens' => 'Zugriffstoken neu generieren...',
'OAuthClient:Name/UseForSMTPMustBeUnique' => 'Die Kombination aus "Login" (%1$s) und "Verwendung für SMTP" (%2$s) existiert bereits.',

View File

@@ -8,8 +8,8 @@
Dict::Add('EN US', 'English', 'English', [
'Menu:CreateMailbox' => 'Create a mailbox...',
'Menu:OAuthClient' => 'OAuth client',
'Menu:OAuthClient+' => '',
'Menu:OAuthClient' => 'OAuth Mail Access',
'Menu:OAuthClient+' => 'Oauth for email access',
'Menu:GenerateTokens' => 'Generate access token...',
'Menu:RegenerateTokens' => 'Regenerate access token...',
@@ -35,7 +35,7 @@ Dict::Add('EN US', 'English', 'English', [
//
Dict::Add('EN US', 'English', 'English', [
'Class:OAuthClient' => 'OAuth Client',
'Class:OAuthClient' => 'OAuth Mail Access',
'Class:OAuthClient/Attribute:provider' => 'Provider',
'Class:OAuthClient/Attribute:provider+' => '',
'Class:OAuthClient/Attribute:name' => 'Login',
@@ -73,7 +73,7 @@ EOF
//
Dict::Add('EN US', 'English', 'English', array(
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure',
'Class:OAuthClientAzure' => 'OAuth Mail Access for Microsoft Azure',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)',
'Class:OAuthClientAzure/Attribute:scope' => 'Scope',
'Class:OAuthClientAzure/Attribute:scope+' => 'Usually default selection is appropriate',
@@ -102,7 +102,7 @@ Dict::Add('EN US', 'English', 'English', array(
//
Dict::Add('EN US', 'English', 'English', array(
'Class:OAuthClientGoogle' => 'OAuth client for Google',
'Class:OAuthClientGoogle' => 'OAuth Mail Access for Google',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)',
'Class:OAuthClientGoogle/Attribute:scope' => 'Scope',
'Class:OAuthClientGoogle/Attribute:scope+' => 'Usually default selection is appropriate',

View File

@@ -8,7 +8,7 @@
Dict::Add('EN GB', 'British English', 'British English', [
'Menu:CreateMailbox' => 'Create a mailbox...',
'Menu:OAuthClient' => 'OAuth client',
'Menu:OAuthClient' => 'OAuth Mail Access',
'Menu:OAuthClient+' => '',
'Menu:GenerateTokens' => 'Generate access token...',
'Menu:RegenerateTokens' => 'Regenerate access token...',
@@ -35,7 +35,7 @@ Dict::Add('EN GB', 'British English', 'British English', [
//
Dict::Add('EN GB', 'British English', 'British English', [
'Class:OAuthClient' => 'OAuth Client',
'Class:OAuthClient' => 'OAuth Mail Access',
'Class:OAuthClient/Attribute:provider' => 'Provider',
'Class:OAuthClient/Attribute:provider+' => '',
'Class:OAuthClient/Attribute:name' => 'Login',
@@ -73,7 +73,7 @@ EOF
//
Dict::Add('EN GB', 'British English', 'British English', array(
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure',
'Class:OAuthClientAzure' => 'OAuth Mail Access for Microsoft Azure',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)',
'Class:OAuthClientAzure/Attribute:scope' => 'Scope',
'Class:OAuthClientAzure/Attribute:scope+' => 'Usually default selection is appropriate',
@@ -102,7 +102,7 @@ Dict::Add('EN GB', 'British English', 'British English', array(
//
Dict::Add('EN GB', 'British English', 'British English', array(
'Class:OAuthClientGoogle' => 'OAuth client for Google',
'Class:OAuthClientGoogle' => 'OAuth Mail Access for Google',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)',
'Class:OAuthClientGoogle/Attribute:scope' => 'Scope',
'Class:OAuthClientGoogle/Attribute:scope+' => 'Usually default selection is appropriate',

View File

@@ -5,10 +5,10 @@
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
* @author Miguel Turrubiates <miguel_tf@yahoo.com>
* @notas Utilizar codificación UTF-8 para mostrar acentos y otros caracteres especiales
* @notas Utilizar codificación UTF-8 para mostrar acentos y otros caracteres especiales
*/
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
'Class:OAuthClient' => 'Cliente OAuth',
'Class:OAuthClient' => 'OAuth Mail Access~~',
'Class:OAuthClient/Attribute:client_id' => 'Id Cliente',
'Class:OAuthClient/Attribute:client_id+' => 'Una cadena larga de caracteres proporcionada por su proveedor de OAuth2',
'Class:OAuthClient/Attribute:client_secret' => 'Secreto del Cliente',
@@ -82,7 +82,7 @@ Borre el campo para recalcular el valor predeterminado',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)',
'Menu:CreateMailbox' => 'Crear un buzón...',
'Menu:GenerateTokens' => 'Generar token de acceso...',
'Menu:OAuthClient' => 'Cliente OAuth',
'Menu:OAuthClient' => 'OAuth Mail Access~~',
'Menu:OAuthClient+' => 'Cliente OAuth',
'Menu:RegenerateTokens' => 'Regenerar token de acceso...',
'OAuthClient:Name/UseForSMTPMustBeUnique' => 'La combinación Inicio de sesión (%1$s) y Uso para SMTP (%2$s) ya se ha utilizado para el Cliente OAuth',

View File

@@ -4,13 +4,13 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*
*/
/**
*
*/
Dict::Add('FR FR', 'French', 'Français', [
'Class:OAuthClient' => 'Client OAuth',
'Class:OAuthClient' => 'Client OAuth pour l\'Accès Mail',
'Class:OAuthClient/Attribute:client_id' => 'ID Client',
'Class:OAuthClient/Attribute:client_id+' => 'Recopier la chaine fournie par votre fournisseur OAuth2',
'Class:OAuthClient/Attribute:client_secret' => 'Code secret du client',
@@ -86,8 +86,8 @@ Pour recalculer la valeur par défaut, il faut effacer le champ',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)',
'Menu:CreateMailbox' => 'Créer une boite mail...',
'Menu:GenerateTokens' => 'Créer un jeton d\'accès...',
'Menu:OAuthClient' => 'Client OAuth',
'Menu:OAuthClient+' => '',
'Menu:OAuthClient' => 'Client OAuth pour l\'Accès Mail',
'Menu:OAuthClient+' => 'Client OAuth pour l\'email',
'Menu:RegenerateTokens' => 'Recréer un jeton d\'accès..',
'OAuthClient:Name/UseForSMTPMustBeUnique' => 'La combinaison Login (%1$s) and Utilisé pour SMTP (%2$s) a déjà été utilisée pour OAuth Client',
'OAuthClient:baseinfo' => 'Information',

View File

@@ -4,13 +4,13 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*
*/
/**
*
*/
Dict::Add('HU HU', 'Hungarian', 'Magyar', [
'Class:OAuthClient' => 'OAuth ügyfél',
'Class:OAuthClient' => 'OAuth Mail Access~~',
'Class:OAuthClient/Attribute:client_id' => 'Ügyfél azonosító',
'Class:OAuthClient/Attribute:client_id+' => 'A long string of characters provided by your OAuth2 provider~~',
'Class:OAuthClient/Attribute:client_secret' => 'Ügyfél kulcs',
@@ -40,7 +40,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Hozzáférési token lejárata',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClientAzure' => 'OAuth ügyfél Microsoft Azure-hoz',
'Class:OAuthClientAzure' => 'OAuth Mail Access for Microsoft Azure~~',
'Class:OAuthClientAzure/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientAzure/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientAzure/Attribute:scope' => 'Scope~~',
@@ -62,7 +62,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple' => 'Simple~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple+' => '~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)',
'Class:OAuthClientGoogle' => 'OAuth ügyfél a Google-höz',
'Class:OAuthClientGoogle' => 'OAuth Mail Access for Google~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientGoogle/Attribute:scope' => 'Scope~~',
@@ -84,7 +84,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)',
'Menu:CreateMailbox' => 'Postafiók létrehozása...',
'Menu:GenerateTokens' => 'Hozzáférési tokenek generálása...',
'Menu:OAuthClient' => 'OAuth ügyfél',
'Menu:OAuthClient' => 'OAuth Mail Access~~',
'Menu:OAuthClient+' => '~~',
'Menu:RegenerateTokens' => 'Hozzáférési tokenek újragenerálása...',
'OAuthClient:Name/UseForSMTPMustBeUnique' => 'The combination Login (%1$s) and Use for SMTP (%2$s) has already been used for OAuth Client~~',

View File

@@ -4,13 +4,13 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*
*/
/**
*
*/
Dict::Add('IT IT', 'Italian', 'Italiano', [
'Class:OAuthClient' => 'Client OAuth',
'Class:OAuthClient' => 'OAuth Mail Access~~',
'Class:OAuthClient/Attribute:client_id' => 'ID cliente',
'Class:OAuthClient/Attribute:client_id+' => 'A long string of characters provided by your OAuth2 provider~~',
'Class:OAuthClient/Attribute:client_secret' => 'Segreto del cliente',
@@ -39,7 +39,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Scadenza del token di accesso',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClientAzure' => 'Client OAuth per Microsoft Azure',
'Class:OAuthClientAzure' => 'OAuth Mail Access for Microsoft Azure~~',
'Class:OAuthClientAzure/Attribute:advanced_scope' => 'Ambito avanzato',
'Class:OAuthClientAzure/Attribute:advanced_scope+' => 'Non appena inserisci qualcosa qui, essa ha la precedenza sulla selezione “Ambito” che viene quindi ignorata',
'Class:OAuthClientAzure/Attribute:scope' => 'Ambito',
@@ -61,7 +61,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple' => 'Semplice',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple+' => '~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)',
'Class:OAuthClientGoogle' => 'Client OAuth per Google',
'Class:OAuthClientGoogle' => 'OAuth Mail Access for Google~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope' => 'Ambito avanzato',
'Class:OAuthClientGoogle/Attribute:advanced_scope+' => 'Non appena inserisci qualcosa qui, essa ha la precedenza sulla selezione “Ambito” che viene quindi ignorata',
'Class:OAuthClientGoogle/Attribute:scope' => 'Ambito',
@@ -83,7 +83,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)',
'Menu:CreateMailbox' => 'Crea una casella di posta...',
'Menu:GenerateTokens' => 'Genera token di accesso...',
'Menu:OAuthClient' => 'Client OAuth',
'Menu:OAuthClient' => 'OAuth Mail Access~~',
'Menu:OAuthClient+' => '~~',
'Menu:RegenerateTokens' => 'Rigenera token di accesso...',
'OAuthClient:Name/UseForSMTPMustBeUnique' => 'La combinazione Login (%1$s) e Uso per SMTP (%2$s) è già stata utilizzata per un altro Client OAuth',

View File

@@ -10,7 +10,7 @@
*
*/
Dict::Add('JA JP', 'Japanese', '日本語', [
'Class:OAuthClient' => 'OAuth Client~~',
'Class:OAuthClient' => 'OAuth Mail Access~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => 'A long string of characters provided by your OAuth2 provider~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
@@ -40,7 +40,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure' => 'OAuth Mail Access for Microsoft Azure~~',
'Class:OAuthClientAzure/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientAzure/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientAzure/Attribute:scope' => 'Scope~~',
@@ -62,7 +62,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple' => 'Simple~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple+' => '~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle' => 'OAuth Mail Access for Google~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientGoogle/Attribute:scope' => 'Scope~~',
@@ -84,7 +84,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:GenerateTokens' => 'Generate access token...~~',
'Menu:OAuthClient' => 'OAuth client~~',
'Menu:OAuthClient' => 'OAuth Mail Access~~',
'Menu:OAuthClient+' => '~~',
'Menu:RegenerateTokens' => 'Regenerate access token...~~',
'OAuthClient:Name/UseForSMTPMustBeUnique' => 'The combination Login (%1$s) and Use for SMTP (%2$s) has already been used for OAuth Client~~',

View File

@@ -11,7 +11,7 @@
* @author Thomas Casteleyn <thomas.casteleyn@super-visions.com>
*/
Dict::Add('NL NL', 'Dutch', 'Nederlands', [
'Class:OAuthClient' => 'OAuth Client~~',
'Class:OAuthClient' => 'OAuth Mail Access~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => 'A long string of characters provided by your OAuth2 provider~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
@@ -41,7 +41,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClient/Attribute:token+' => '',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '',
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure' => 'OAuth Mail Access for Microsoft Azure~~',
'Class:OAuthClientAzure/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientAzure/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientAzure/Attribute:scope' => 'Scope~~',
@@ -63,7 +63,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple' => 'Eenvoudig',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple+' => '',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)',
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle' => 'OAuth Mail Access for Google~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientGoogle/Attribute:scope' => 'Scope~~',
@@ -85,7 +85,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)',
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:GenerateTokens' => 'Generate access token...~~',
'Menu:OAuthClient' => 'OAuth client~~',
'Menu:OAuthClient' => 'OAuth Mail Access~~',
'Menu:OAuthClient+' => '',
'Menu:RegenerateTokens' => 'Regenerate access token...~~',
'OAuthClient:Name/UseForSMTPMustBeUnique' => 'The combination Login (%1$s) and Use for SMTP (%2$s) has already been used for OAuth Client~~',

View File

@@ -4,13 +4,13 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*
*/
/**
*
*/
Dict::Add('PL PL', 'Polish', 'Polski', [
'Class:OAuthClient' => 'Klient OAuth',
'Class:OAuthClient' => 'OAuth Mail Access~~',
'Class:OAuthClient/Attribute:client_id' => 'Id klienta',
'Class:OAuthClient/Attribute:client_id+' => 'Długi ciąg znaków dostarczony przez dostawcę protokołu OAuth2',
'Class:OAuthClient/Attribute:client_secret' => 'Sekretny ciąg',
@@ -80,7 +80,7 @@ Usuń pole, aby ponownie obliczyć wartość domyślną',
'Class:OAuthClient/Attribute:token+' => '',
'Class:OAuthClient/Attribute:token_expiration' => 'Wygaśnięcie tokenu dostępu',
'Class:OAuthClient/Attribute:token_expiration+' => '',
'Class:OAuthClientAzure' => 'Klient OAuth dla Microsoft Azure',
'Class:OAuthClientAzure' => 'OAuth Mail Access for Microsoft Azure~~',
'Class:OAuthClientAzure/Attribute:advanced_scope' => 'Zaawansowany zakres',
'Class:OAuthClientAzure/Attribute:advanced_scope+' => 'Gdy tylko coś tu wpiszesz, będzie to miało pierwszeństwo przed wyborem „Zakres”, który zostanie następnie zignorowany',
'Class:OAuthClientAzure/Attribute:scope' => 'Zakres',
@@ -150,7 +150,7 @@ Usuń pole, aby ponownie obliczyć wartość domyślną',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple' => 'Prosty',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple+' => '',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)',
'Class:OAuthClientGoogle' => 'Klient OAuth dla Google',
'Class:OAuthClientGoogle' => 'OAuth Mail Access for Google~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope' => 'Zaawansowany zakres',
'Class:OAuthClientGoogle/Attribute:advanced_scope+' => 'Gdy tylko coś tu wpiszesz, będzie to miało pierwszeństwo przed wyborem „Zakres”, który zostanie następnie zignorowany',
'Class:OAuthClientGoogle/Attribute:scope' => 'Zakres',
@@ -220,7 +220,7 @@ Usuń pole, aby ponownie obliczyć wartość domyślną',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)',
'Menu:CreateMailbox' => 'Utwórz skrzynkę pocztową...',
'Menu:GenerateTokens' => 'Wygeneruj token dostępu...',
'Menu:OAuthClient' => 'Klient OAuth',
'Menu:OAuthClient' => 'OAuth Mail Access~~',
'Menu:OAuthClient+' => '',
'Menu:RegenerateTokens' => 'Wygeneruj ponownie token dostępu...',
'OAuthClient:Name/UseForSMTPMustBeUnique' => 'Kombinacja Loginu (%1$s) i SMTP (%2$s) była już użyta dla klienta OAuth',

View File

@@ -10,7 +10,7 @@
*
*/
Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
'Class:OAuthClient' => 'OAuth Client~~',
'Class:OAuthClient' => 'OAuth Mail Access~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => 'A long string of characters provided by your OAuth2 provider~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
@@ -40,7 +40,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure' => 'OAuth Mail Access for Microsoft Azure~~',
'Class:OAuthClientAzure/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientAzure/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientAzure/Attribute:scope' => 'Scope~~',
@@ -62,7 +62,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple' => 'Simple~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple+' => '~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle' => 'OAuth Mail Access for Google~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientGoogle/Attribute:scope' => 'Scope~~',
@@ -84,7 +84,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:GenerateTokens' => 'Generate access token...~~',
'Menu:OAuthClient' => 'OAuth client~~',
'Menu:OAuthClient' => 'OAuth Mail Access~~',
'Menu:OAuthClient+' => '~~',
'Menu:RegenerateTokens' => 'Regenerate access token...~~',
'OAuthClient:Name/UseForSMTPMustBeUnique' => 'The combination Login (%1$s) and Use for SMTP (%2$s) has already been used for OAuth Client~~',

View File

@@ -10,7 +10,7 @@
*
*/
Dict::Add('RU RU', 'Russian', 'Русский', [
'Class:OAuthClient' => 'OAuth Client~~',
'Class:OAuthClient' => 'OAuth Mail Access~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => 'A long string of characters provided by your OAuth2 provider~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
@@ -40,7 +40,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure' => 'OAuth Mail Access for Microsoft Azure~~',
'Class:OAuthClientAzure/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientAzure/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientAzure/Attribute:scope' => 'Scope~~',
@@ -62,7 +62,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple' => 'Simple~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple+' => '~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle' => 'OAuth Mail Access for Google~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientGoogle/Attribute:scope' => 'Scope~~',
@@ -84,7 +84,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:GenerateTokens' => 'Generate access token...~~',
'Menu:OAuthClient' => 'OAuth client~~',
'Menu:OAuthClient' => 'OAuth Mail Access~~',
'Menu:OAuthClient+' => '~~',
'Menu:RegenerateTokens' => 'Regenerate access token...~~',
'OAuthClient:Name/UseForSMTPMustBeUnique' => 'The combination Login (%1$s) and Use for SMTP (%2$s) has already been used for OAuth Client~~',

View File

@@ -10,7 +10,7 @@
*
*/
Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
'Class:OAuthClient' => 'OAuth Client~~',
'Class:OAuthClient' => 'OAuth Mail Access~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => 'A long string of characters provided by your OAuth2 provider~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
@@ -38,7 +38,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure' => 'OAuth Mail Access for Microsoft Azure~~',
'Class:OAuthClientAzure/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientAzure/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientAzure/Attribute:scope' => 'Scope~~',
@@ -60,7 +60,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple' => 'Simple~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple+' => '~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle' => 'OAuth Mail Access for Google~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientGoogle/Attribute:scope' => 'Scope~~',
@@ -82,7 +82,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:GenerateTokens' => 'Generate access token...~~',
'Menu:OAuthClient' => 'OAuth client~~',
'Menu:OAuthClient' => 'OAuth Mail Access~~',
'Menu:OAuthClient+' => '~~',
'Menu:RegenerateTokens' => 'Regenerate access token...~~',
'OAuthClient:Name/UseForSMTPMustBeUnique' => 'The combination Login (%1$s) and Use for SMTP (%2$s) has already been used for OAuth Client~~',

View File

@@ -10,7 +10,7 @@
*
*/
Dict::Add('TR TR', 'Turkish', 'Türkçe', [
'Class:OAuthClient' => 'OAuth Client~~',
'Class:OAuthClient' => 'OAuth Mail Access~~',
'Class:OAuthClient/Attribute:client_id' => 'Client id~~',
'Class:OAuthClient/Attribute:client_id+' => 'A long string of characters provided by your OAuth2 provider~~',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret~~',
@@ -40,7 +40,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration~~',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure~~',
'Class:OAuthClientAzure' => 'OAuth Mail Access for Microsoft Azure~~',
'Class:OAuthClientAzure/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientAzure/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientAzure/Attribute:scope' => 'Scope~~',
@@ -62,7 +62,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple' => 'Simple~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple+' => '~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)~~',
'Class:OAuthClientGoogle' => 'OAuth client for Google~~',
'Class:OAuthClientGoogle' => 'OAuth Mail Access for Google~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope' => 'Advanced scope~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence over the “Scope” selection which is then ignored~~',
'Class:OAuthClientGoogle/Attribute:scope' => 'Scope~~',
@@ -84,7 +84,7 @@ Erase the field to recalculate default value~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)~~',
'Menu:CreateMailbox' => 'Create a mailbox...~~',
'Menu:GenerateTokens' => 'Generate access token...~~',
'Menu:OAuthClient' => 'OAuth client~~',
'Menu:OAuthClient' => 'OAuth Mail Access~~',
'Menu:OAuthClient+' => '~~',
'Menu:RegenerateTokens' => 'Regenerate access token...~~',
'OAuthClient:Name/UseForSMTPMustBeUnique' => 'The combination Login (%1$s) and Use for SMTP (%2$s) has already been used for OAuth Client~~',

View File

@@ -4,99 +4,122 @@
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
*
*/
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Menu:CreateMailbox' => '创建邮箱...',
'Menu:OAuthClient' => 'OAuth Mail Access~~',
'Menu:OAuthClient+' => '',
'Menu:GenerateTokens' => '生成访问令牌...',
'Menu:RegenerateTokens' => '重新生成访问令牌...',
'itop-oauth-client/Operation:CreateMailBox/Title' => '邮箱创建',
'itop-oauth-client:UsedForSMTP' => '此OAuth客户端用户SMTP',
'itop-oauth-client:TestSMTP' => '发送测试邮件',
'itop-oauth-client:MissingOAuthClient' => '没有Oauth客户端给用户%1$s',
'itop-oauth-client:Message:MissingToken' => '使用OAuth客户端前生成访问令牌',
'itop-oauth-client:Message:RegenerateToken' => '重新生成访问令牌以适用更改',
'itop-oauth-client:Message:TokenCreated' => '访问令牌已生成',
'itop-oauth-client:Message:TokenRecreated' => '访问令牌已重新生成',
'itop-oauth-client:Message:TokenError' => '由于服务错误没有生成访问令牌',
'OAuthClient:Name/UseForSMTPMustBeUnique' => '此组合登录 (%1$s) 和使用于SMTP (%2$s) 已经在OAuth客户端使用',
'OAuthClient:baseinfo' => '基本信息',
'OAuthClient:scope' => '范围',
]);
//
// Class: OAuthClient
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:OAuthClient' => 'OAuth客户端',
'Class:OAuthClient/Attribute:client_id' => '客户端编号',
'Class:OAuthClient/Attribute:client_id+' => 'A long string of characters provided by your OAuth2 provider~~',
'Class:OAuthClient/Attribute:client_secret' => '客户端密码',
'Class:OAuthClient/Attribute:client_secret+' => 'Another long string of characters provided by your OAuth2 provider~~',
'Class:OAuthClient/Attribute:description' => '备注',
'Class:OAuthClient/Attribute:description+' => '~~',
'Class:OAuthClient/Attribute:mailbox_list' => '邮箱列表',
'Class:OAuthClient/Attribute:mailbox_list+' => '~~',
'Class:OAuthClient/Attribute:name' => '登录',
'Class:OAuthClient/Attribute:name+' => 'In general, this is your email address~~',
'Class:OAuthClient' => 'OAuth Mail Access~~',
'Class:OAuthClient/Attribute:provider' => '提供商',
'Class:OAuthClient/Attribute:provider+' => '~~',
'Class:OAuthClient/Attribute:redirect_url' => '重定向URL',
'Class:OAuthClient/Attribute:redirect_url+' => 'This url must be copied in the OAuth2 configuration of the provider
Erase the field to recalculate default value~~',
'Class:OAuthClient/Attribute:refresh_token' => '刷新令牌',
'Class:OAuthClient/Attribute:refresh_token+' => '~~',
'Class:OAuthClient/Attribute:refresh_token_expiration' => '刷新令牌有效期',
'Class:OAuthClient/Attribute:refresh_token_expiration+' => '~~',
'Class:OAuthClient/Attribute:scope' => '范围',
'Class:OAuthClient/Attribute:scope+' => '~~',
'Class:OAuthClient/Attribute:name' => '登录',
'Class:OAuthClient/Attribute:name+' => 'In general, this is your email address~~',
'Class:OAuthClient/Attribute:status' => '状态',
'Class:OAuthClient/Attribute:status+' => '创建后, 通过 "生成访问令牌" 来使用此OAuth 客户端',
'Class:OAuthClient/Attribute:status/Value:active' => '已生成访问令牌',
'Class:OAuthClient/Attribute:status/Value:inactive' => '没有访问令牌',
'Class:OAuthClient/Attribute:description' => '备注',
'Class:OAuthClient/Attribute:description+' => '~~',
'Class:OAuthClient/Attribute:client_id' => '客户端编号',
'Class:OAuthClient/Attribute:client_id+' => 'A long string of characters provided by your OAuth2 provider~~',
'Class:OAuthClient/Attribute:client_secret' => '客户端密码',
'Class:OAuthClient/Attribute:client_secret+' => 'Another long string of characters provided by your OAuth2 provider~~',
'Class:OAuthClient/Attribute:refresh_token' => '刷新令牌',
'Class:OAuthClient/Attribute:refresh_token+' => '~~',
'Class:OAuthClient/Attribute:refresh_token_expiration' => '刷新令牌有效期',
'Class:OAuthClient/Attribute:refresh_token_expiration+' => '~~',
'Class:OAuthClient/Attribute:token' => '访问令牌',
'Class:OAuthClient/Attribute:token+' => '~~',
'Class:OAuthClient/Attribute:token_expiration' => '访问令牌有效期',
'Class:OAuthClient/Attribute:token_expiration+' => '~~',
'Class:OAuthClientAzure' => '用于微软Azure的OAuth客户端',
'Class:OAuthClientAzure/Attribute:advanced_scope' => '高级范围',
'Class:OAuthClientAzure/Attribute:advanced_scope+' => '您在此输入的内容将优先于 "范围" 选择并导致其被忽略',
'Class:OAuthClient/Attribute:redirect_url' => 'Redirect url',
'Class:OAuthClient/Attribute:redirect_url+' => <<<EOF
This url must be copied in the OAuth2 configuration of the provider
Erase the field to recalculate default value
EOF
,
'Class:OAuthClient/Attribute:mailbox_list' => '邮箱列表',
'Class:OAuthClient/Attribute:mailbox_list+' => '~~',
]);
//
// Class: OAuthClientAzure
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:OAuthClientAzure' => 'OAuth Mail Access for Microsoft Azure~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)',
'Class:OAuthClientAzure/Attribute:scope' => '范围',
'Class:OAuthClientAzure/Attribute:scope+' => '通常情况下使用默认选择最合适',
'Class:OAuthClientAzure/Attribute:scope/Value:IMAP' => 'IMAP',
'Class:OAuthClientAzure/Attribute:scope/Value:IMAP+' => '~~',
'Class:OAuthClientAzure/Attribute:scope/Value:SMTP' => 'SMTP',
'Class:OAuthClientAzure/Attribute:scope/Value:SMTP+' => '~~',
'Class:OAuthClientAzure/Attribute:tenant' => 'Tenant~~',
'Class:OAuthClientAzure/Attribute:tenant+' => 'Tenant ID of the configured application. For multi-tenant application, use "common".~~',
'Class:OAuthClientAzure/Attribute:used_for_smtp' => '使用于SMTP',
'Class:OAuthClientAzure/Attribute:used_for_smtp+' => '如果您需要系统使用其发送邮件, 则至少需要有一个OAuth客户端标记为 "是"',
'Class:OAuthClientAzure/Attribute:used_for_smtp/Value:no' => '否',
'Class:OAuthClientAzure/Attribute:used_for_smtp/Value:yes' => '是',
'Class:OAuthClientAzure/Attribute:scope/Value:IMAP' => 'IMAP',
'Class:OAuthClientAzure/Attribute:scope/Value:IMAP+' => '~~',
'Class:OAuthClientAzure/Attribute:advanced_scope' => '高级范围',
'Class:OAuthClientAzure/Attribute:advanced_scope+' => '您在此输入的内容将优先于 "范围" 选择并导致其被忽略',
'Class:OAuthClientAzure/Attribute:used_scope' => '使用范围',
'Class:OAuthClientAzure/Attribute:used_scope+' => '~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:advanced' => '高级',
'Class:OAuthClientAzure/Attribute:used_scope/Value:advanced+' => '~~',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple' => '精简',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple+' => '~~',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)',
'Class:OAuthClientGoogle' => '用于Google的OAuth客户端',
'Class:OAuthClientGoogle/Attribute:advanced_scope' => '高级范围',
'Class:OAuthClientGoogle/Attribute:advanced_scope+' => '您在此输入的内容将优先于 "范围" 选择并导致其被忽略',
'Class:OAuthClientAzure/Attribute:used_scope/Value:advanced' => '高级',
'Class:OAuthClientAzure/Attribute:used_scope/Value:advanced+' => '~~',
'Class:OAuthClientAzure/Attribute:used_for_smtp' => '使用于SMTP',
'Class:OAuthClientAzure/Attribute:used_for_smtp+' => '如果您需要系统使用其发送邮件, 则至少需要有一个OAuth客户端标记为 "是"',
'Class:OAuthClientAzure/Attribute:used_for_smtp/Value:yes' => '是',
'Class:OAuthClientAzure/Attribute:used_for_smtp/Value:no' => '否',
'Class:OAuthClientAzure/Attribute:tenant' => 'Tenant~~',
'Class:OAuthClientAzure/Attribute:tenant+' => 'Tenant ID of the configured application. For multi-tenant application, use "common".~~',
]);
//
// Class: OAuthClientGoogle
//
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:OAuthClientGoogle' => 'OAuth Mail Access for Google~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)',
'Class:OAuthClientGoogle/Attribute:scope' => '范围',
'Class:OAuthClientGoogle/Attribute:scope+' => '通常情况下使用默认选择最合适',
'Class:OAuthClientGoogle/Attribute:scope/Value:IMAP' => 'IMAP',
'Class:OAuthClientGoogle/Attribute:scope/Value:IMAP+' => '~~',
'Class:OAuthClientGoogle/Attribute:scope/Value:SMTP' => 'SMTP',
'Class:OAuthClientGoogle/Attribute:scope/Value:SMTP+' => '~~',
'Class:OAuthClientGoogle/Attribute:used_for_smtp' => '使用与SMTP',
'Class:OAuthClientGoogle/Attribute:used_for_smtp+' => '如果您需要系统使用其发送邮件, 则至少需要有一个OAuth客户端标记为 "是"',
'Class:OAuthClientGoogle/Attribute:used_for_smtp/Value:no' => '',
'Class:OAuthClientGoogle/Attribute:used_for_smtp/Value:yes' => '是',
'Class:OAuthClientGoogle/Attribute:scope/Value:IMAP' => 'IMAP',
'Class:OAuthClientGoogle/Attribute:scope/Value:IMAP+' => '~~',
'Class:OAuthClientGoogle/Attribute:advanced_scope' => '高级范围',
'Class:OAuthClientGoogle/Attribute:advanced_scope+' => '您在此输入的内容将优先于 "范围" 选择并导致其被忽略',
'Class:OAuthClientGoogle/Attribute:used_scope' => '使用范围',
'Class:OAuthClientGoogle/Attribute:used_scope+' => '~~',
'Class:OAuthClientGoogle/Attribute:used_scope/Value:advanced' => '高级',
'Class:OAuthClientGoogle/Attribute:used_scope/Value:advanced+' => '~~',
'Class:OAuthClientGoogle/Attribute:used_scope/Value:simple' => '精简',
'Class:OAuthClientGoogle/Attribute:used_scope/Value:simple+' => '~~',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)',
'Menu:CreateMailbox' => '创建邮箱...',
'Menu:GenerateTokens' => '生成访问令牌...',
'Menu:OAuthClient' => 'OAuth客户端',
'Menu:OAuthClient+' => '~~',
'Menu:RegenerateTokens' => '重新生成访问令牌...',
'OAuthClient:Name/UseForSMTPMustBeUnique' => '此组合登录 (%1$s) 和使用于SMTP (%2$s) 已经在OAuth客户端使用',
'OAuthClient:baseinfo' => '基本信息',
'OAuthClient:scope' => '范围',
'itop-oauth-client/Operation:CreateMailBox/Title' => '邮箱创建',
'itop-oauth-client:Message:MissingToken' => '使用OAuth客户端前生成访问令牌',
'itop-oauth-client:Message:RegenerateToken' => '重新生成访问令牌以适用更改',
'itop-oauth-client:Message:TokenCreated' => '访问令牌已生成',
'itop-oauth-client:Message:TokenError' => '由于服务错误没有生成访问令牌',
'itop-oauth-client:Message:TokenRecreated' => '访问令牌已重新生成',
'itop-oauth-client:MissingOAuthClient' => '没有Oauth客户端给用户%1$s',
'itop-oauth-client:TestSMTP' => '发送测试邮件',
'itop-oauth-client:UsedForSMTP' => '此OAuth客户端用户SMTP',
'Class:OAuthClientGoogle/Attribute:used_scope/Value:advanced' => '高级',
'Class:OAuthClientGoogle/Attribute:used_scope/Value:advanced+' => '~~',
'Class:OAuthClientGoogle/Attribute:used_for_smtp' => '使用与SMTP',
'Class:OAuthClientGoogle/Attribute:used_for_smtp+' => '如果您需要系统使用其发送邮件, 则至少需要有一个OAuth客户端标记为 "是"',
'Class:OAuthClientGoogle/Attribute:used_for_smtp/Value:yes' => '',
'Class:OAuthClientGoogle/Attribute:used_for_smtp/Value:no' => '否',
]);

View File

@@ -50,7 +50,7 @@ class PopupMenuExtension implements \iPopupMenuExtension
if ($bHasToken) {
$aScopes = $oObj->Get('scope')->GetValues();
if (in_array('IMAP', $aScopes)) {
if (in_array('IMAP', $aScopes) && class_exists('MailInboxOAuth')) {
$aParams = $oAppContext->GetAsHash();
$sMenu = 'Menu:CreateMailbox';
$sObjClass = get_class($oObj);

View File

@@ -1,114 +1,156 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
// Portal
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Brick:Portal:AggregatePage:DefaultTitle' => '仪表盘',
'Brick:Portal:Browse:Action:Create' => '新建',
'Brick:Portal:Browse:Action:CreateObjectFromThis' => '新建%1$s',
'Brick:Portal:Browse:Action:Drilldown' => '明细',
'Brick:Portal:Browse:Action:Edit' => '编辑',
'Brick:Portal:Browse:Action:View' => '详情',
'Brick:Portal:Browse:Filter:NoData' => '没有项目',
'Brick:Portal:Browse:Mode:List' => '列表',
'Brick:Portal:Browse:Mode:Mosaic' => '嵌套',
'Brick:Portal:Browse:Mode:Tree' => '树形',
'Brick:Portal:Browse:Name' => '浏览项目',
'Brick:Portal:Browse:Tree:CollapseAll' => '全部收起',
'Brick:Portal:Browse:Tree:ExpandAll' => '全部展开',
'Brick:Portal:Create:ChooseType' => '请选择类型',
'Brick:Portal:Create:Name' => '快速创建',
'Brick:Portal:Filter:Name' => '预筛选组件',
'Brick:Portal:Filter:SearchInput:Placeholder' => '例如. 连接wifi',
'Brick:Portal:Filter:SearchInput:Submit' => '搜索',
'Brick:Portal:Manage:All' => '全部',
'Brick:Portal:Manage:DisplayMode:bar-chart' => '条形图',
'Brick:Portal:Manage:DisplayMode:list' => '列表',
'Brick:Portal:Manage:DisplayMode:pie-chart' => '饼图',
'Brick:Portal:Manage:Group' => '分组',
'Brick:Portal:Manage:Name' => '管理项目',
'Brick:Portal:Manage:Others' => 'Others',
'Brick:Portal:Manage:Table:ItemActions' => '操作',
'Brick:Portal:Manage:Table:NoData' => '没有项目.',
'Brick:Portal:Manage:fct:avg' => '平均',
'Brick:Portal:Manage:fct:count' => '个数',
'Brick:Portal:Manage:fct:max' => '最大',
'Brick:Portal:Manage:fct:min' => '最小',
'Brick:Portal:Manage:fct:sum' => '总数',
'Brick:Portal:Object:Copy:CopiedTooltip' => '已复制',
'Brick:Portal:Object:Copy:TextToCopy' => '%2$s',
'Brick:Portal:Object:Copy:Tooltip' => '复制对象链接',
'Brick:Portal:Object:Form:Create:Title' => '新建%1$s',
'Brick:Portal:Object:Form:Edit:Title' => '正在更新%2$s (%1$s)',
'Brick:Portal:Object:Form:Message:ObjectSaved' => '已保存%1$s',
'Brick:Portal:Object:Form:Message:Saved' => '已保存',
'Brick:Portal:Object:Form:Stimulus:Title' => '请填写下列信息:',
'Brick:Portal:Object:Form:View:Title' => '%1$s: %2$s',
'Brick:Portal:Object:Name' => '对象',
'Brick:Portal:Object:Search:Hierarchy:Title' => '选择%1$s (%2$s)',
'Brick:Portal:Object:Search:Regular:Title' => '选择%1$s (%2$s)',
'Brick:Portal:UserProfile:Name' => '用户资料',
'Brick:Portal:UserProfile:Navigation:Dropdown:Logout' => '注销',
'Brick:Portal:UserProfile:Navigation:Dropdown:MyProfil' => '我的资料',
'Brick:Portal:UserProfile:Password:CantChangeContactAdministrator' => '要修改密码, 请联系管理员',
'Brick:Portal:UserProfile:Password:CantChangeForUnknownReason' => '无法修改密码, 请联系管理员',
'Brick:Portal:UserProfile:Password:ChoosePassword' => '新密码',
'Brick:Portal:UserProfile:Password:ConfirmPassword' => '确认密码',
'Brick:Portal:UserProfile:Password:Title' => '密码',
'Brick:Portal:UserProfile:PersonalInformations:Title' => '人员信息',
'Brick:Portal:UserProfile:Photo:Title' => '头像',
'Page:DefaultTitle' => '%1$s 用户门户',
'Page:PleaseWait' => '请稍候...',
'Page:Home' => '主页',
'Page:GoPortalHome' => '主页面',
'Page:GoPreviousPage' => '上一页',
'Page:ReloadPage' => '重新加载',
'Portal:Button:Submit' => '提交',
'Portal:Button:Apply' => '更新',
'Portal:Button:Cancel' => '取消',
'Portal:Button:Close' => '关闭',
'Portal:Button:Add' => '添加',
'Portal:Button:Remove' => '移除',
'Portal:Button:Delete' => '删除',
'Portal:EnvironmentBanner:Title' => '您目前处于<strong>%1$s</strong>模式',
'Portal:EnvironmentBanner:GoToProduction' => '回到产品模式',
'Error:HTTP:400' => '请求错误',
'Error:HTTP:401' => '认证错误',
'Error:HTTP:404' => '页面找不到',
'Error:HTTP:500' => '啊! 发生了错误.',
'Error:HTTP:GetHelp' => '如果问题仍然存在,请联系管理员.',
'Error:XHR:Fail' => '无法加载数据, 请联系管理员',
'Page:DefaultTitle' => ITOP_APPLICATION_SHORT.'用户门户',
'Page:GoPortalHome' => '主页面',
'Page:GoPreviousPage' => '上一页',
'Page:Home' => '主页',
'Page:PleaseWait' => '请稍后...',
'Page:ReloadPage' => '重新加载',
'Portal:Attachments:DropZone:Message' => '把文件添加为附件',
'Portal:Autocomplete:NoResult' => '没有数据',
'Portal:Button:Add' => '添加',
'Portal:Button:Apply' => '更新',
'Portal:Button:Cancel' => '取消',
'Portal:Button:Close' => '关闭',
'Portal:Button:Delete' => '删除',
'Portal:Button:Remove' => '移除',
'Portal:Button:Submit' => '提交',
'Portal:Calendar-FirstDayOfWeek' => 'zh-cn',
'Portal:Datatables:Language:DisplayLength:All' => '全部',
'Portal:Datatables:Language:EmptyTable' => '表格中没有数据',
'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' => '最多筛选 _MAX_ 项',
'Portal:Datatables:Language:LengthMenu' => '每页显示 _MENU_ 项',
'Portal:Datatables:Language:EmptyTable' => '表格中没有数据',
'Portal:Datatables:Language:DisplayLength:All' => '全部',
'Portal:Datatables:Language:Paginate:First' => '首页',
'Portal:Datatables:Language:Paginate:Last' => '尾页',
'Portal:Datatables:Language:Paginate:Next' => '下一页',
'Portal:Datatables:Language:Paginate:Previous' => '上一页',
'Portal:Datatables:Language:Processing' => '请稍后...',
'Portal:Datatables:Language:Search' => '筛选器:',
'Portal:Datatables:Language:Paginate:Next' => '下一页',
'Portal:Datatables:Language:Paginate:Last' => '尾页',
'Portal:Datatables:Language:Sort:Ascending' => '升序',
'Portal:Datatables:Language:Sort:Descending' => '降序',
'Portal:Datatables:Language:ZeroRecords' => '没有结果',
'Portal:EnvironmentBanner:GoToProduction' => '回到产品模式',
'Portal:EnvironmentBanner:Title' => '您目前处于<strong>%1$s</strong>模式',
'Portal:Error:ObjectCannotBeCreated' => '错误: 无法创建对象. 请在再次提交表单前检查相关对象和附件.',
'Portal:Error:ObjectCannotBeUpdated' => '错误: 无法更新对象. 请在再次提交表单前检查相关对象和附件.',
'Portal:ErrorUserLoggedOut' => '您已退出,请重新登录.',
'Portal:Autocomplete:NoResult' => '没有数据',
'Portal:Attachments:DropZone:Message' => '把文件添加为附件',
'Portal:File:None' => '没有文件',
'Portal:File:DisplayInfo' => '<a href="%2$s" class="file_download_link">%1$s</a>',
'Portal:File:DisplayInfo+' => '%1$s (%2$s) <a href="%3$s" class="file_open_link" target="_blank">打开</a> / <a href="%4$s" class="file_download_link">下载</a>',
'Portal:File:None' => '没有文件',
'Portal:Calendar-FirstDayOfWeek' => 'zh-cn',
]);
// Object form
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Portal:Form:Caselog:Entry:Close:Tooltip' => '关闭此条目',
'Portal:Form:Close:Warning' => '确定要离开表单吗? 已输入数据会丢失',
'Portal:Error:ObjectCannotBeCreated' => '错误: 无法创建对象. 请在再次提交表单前检查相关对象和附件.',
'Portal:Error:ObjectCannotBeUpdated' => '错误: 无法更新对象. 请在再次提交表单前检查相关对象和附件.',
]);
// UserProfile brick
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Brick:Portal:UserProfile:Name' => '用户资料',
'Brick:Portal:UserProfile:Navigation:Dropdown:MyProfil' => '我的资料',
'Brick:Portal:UserProfile:Navigation:Dropdown:Logout' => '注销',
'Brick:Portal:UserProfile:Password:Title' => '密码',
'Brick:Portal:UserProfile:Password:ChoosePassword' => '新密码',
'Brick:Portal:UserProfile:Password:ConfirmPassword' => '确认密码',
'Brick:Portal:UserProfile:Password:CantChangeContactAdministrator' => '要修改密码, 请联系管理员',
'Brick:Portal:UserProfile:Password:CantChangeForUnknownReason' => '无法修改密码, 请联系管理员',
'Brick:Portal:UserProfile:PersonalInformations:Title' => '人员信息',
'Brick:Portal:UserProfile:Photo:Title' => '头像',
]);
// AggregatePageBrick
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Brick:Portal:AggregatePage:DefaultTitle' => '仪表盘',
]);
// BrowseBrick brick
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Brick:Portal:Browse:Name' => '浏览项目',
'Brick:Portal:Browse:Mode:List' => '列表',
'Brick:Portal:Browse:Mode:Tree' => '树形',
'Brick:Portal:Browse:Mode:Mosaic' => '嵌套',
'Brick:Portal:Browse:Action:Drilldown' => '明细',
'Brick:Portal:Browse:Action:View' => '详情',
'Brick:Portal:Browse:Action:Edit' => '编辑',
'Brick:Portal:Browse:Action:Create' => '新建',
'Brick:Portal:Browse:Action:CreateObjectFromThis' => '新建 %1$s',
'Brick:Portal:Browse:Tree:ExpandAll' => '全部展开',
'Brick:Portal:Browse:Tree:CollapseAll' => '全部收起',
'Brick:Portal:Browse:Filter:NoData' => '没有项目',
]);
// ManageBrick brick
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Brick:Portal:Manage:Name' => '管理项目',
'Brick:Portal:Manage:Table:NoData' => '没有项目.',
'Brick:Portal:Manage:Table:ItemActions' => '操作',
'Brick:Portal:Manage:DisplayMode:list' => '列表',
'Brick:Portal:Manage:DisplayMode:pie-chart' => '饼图',
'Brick:Portal:Manage:DisplayMode:bar-chart' => '条形图',
'Brick:Portal:Manage:Others' => 'Others',
'Brick:Portal:Manage:All' => '全部',
'Brick:Portal:Manage:Group' => '分组',
'Brick:Portal:Manage:fct:count' => '个数',
'Brick:Portal:Manage:fct:sum' => '总数',
'Brick:Portal:Manage:fct:avg' => '平均',
'Brick:Portal:Manage:fct:min' => '最小',
'Brick:Portal:Manage:fct:max' => '最大',
]);
// ObjectBrick brick
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Brick:Portal:Object:Name' => '对象',
'Brick:Portal:Object:Form:Create:Title' => '新建 %1$s',
'Brick:Portal:Object:Form:Edit:Title' => '正在更新 %2$s (%1$s)',
'Brick:Portal:Object:Form:View:Title' => '%1$s: %2$s',
'Brick:Portal:Object:Form:Stimulus:Title' => '请填写下列信息:',
'Brick:Portal:Object:Form:Message:Saved' => '已保存',
'Brick:Portal:Object: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' => '%2$s',
'Brick:Portal:Object:Copy:Tooltip' => '复制对象链接',
'Brick:Portal:Object:Copy:CopiedTooltip' => '已复制',
]);
// CreateBrick brick
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Brick:Portal:Create:Name' => '快速创建',
'Brick:Portal:Create:ChooseType' => '请选择类型',
]);
// Filter brick
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Brick:Portal:Filter:Name' => '预筛选组件',
'Brick:Portal:Filter:SearchInput:Placeholder' => '例如. 连接wifi',
'Brick:Portal:Filter:SearchInput:Submit' => '搜索',
]);

View File

@@ -1,19 +1,13 @@
framework:
cache:
# Unique name of your app: used to compute stable namespaces for cache keys.
#prefix_seed: your_vendor_name/app_name
# Unique name of your app: used to compute stable namespaces for cache keys.
prefix_seed: combodo/itop
# The "app" cache stores to the filesystem by default.
# The data in this cache should persist between deploys.
# Other options include:
# filesystem
app: cache.adapter.filesystem
# Redis
#app: cache.adapter.redis
#default_redis_provider: redis://localhost
# Namespaced pools use the above "app" backend by default
pools:
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
#app: cache.adapter.apcu
# Namespaced pools use the above "app" backend by default
#pools:
#my.dedicated.cache: null
templates_cache_pool:
adapter: cache.app

File diff suppressed because one or more lines are too long

View File

@@ -18,7 +18,7 @@
@import 'variables.scss';
@import '../../../../../node_modules/ckeditor5-itop-build/build/styles/compiled-theme';
@import '../../../../../css/common/vendors/_highlightjs.scss';
@import '../../../../../css/common/main.scss';
/*!

View File

@@ -23,9 +23,13 @@ namespace Combodo\iTop\Portal\Brick;
require_once APPROOT.'/core/moduledesign.class.inc.php';
require_once APPROOT.'/setup/compiler.class.inc.php';
use Combodo\iTop\DesignElement;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesProviderInterface;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplateDefinitionDto;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesProviderService;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesRegister;
use DOMFormatException;
use ModuleDesign;
use Combodo\iTop\DesignElement;
/**
* Description of AbstractBrick
@@ -36,7 +40,7 @@ use Combodo\iTop\DesignElement;
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.3.0
*/
abstract class AbstractBrick
abstract class AbstractBrick implements TemplatesProviderInterface
{
/** @var string ENUM_DATA_LOADING_LAZY */
const ENUM_DATA_LOADING_LAZY = 'lazy';
@@ -53,7 +57,7 @@ abstract class AbstractBrick
const DEFAULT_VISIBLE = true;
/** @var float DEFAULT_RANK */
const DEFAULT_RANK = 1.0;
/** @var string|null DEFAULT_PAGE_TEMPLATE_PATH */
/** @var string|null DEFAULT_PAGE_TEMPLATE_PATH @deprecated since 3.2.1 */
const DEFAULT_PAGE_TEMPLATE_PATH = null;
/** @var string DEFAULT_TITLE */
const DEFAULT_TITLE = '';
@@ -65,6 +69,8 @@ abstract class AbstractBrick
const DEFAULT_ALLOWED_PROFILES_OQL = '';
/** @var string DEFAULT_DENIED_PROFILES_OQL */
const DEFAULT_DENIED_PROFILES_OQL = '';
/** @var string TEMPLATES_BASE_PATH */
const TEMPLATES_BASE_PATH = 'itop-portal-base/portal/templates/bricks/';
/** @var string $sId */
protected $sId;
@@ -76,7 +82,7 @@ abstract class AbstractBrick
protected $bVisible;
/** @var float $fRank */
protected $fRank;
/** @var string|null $sPageTemplatePath */
/** @var string|null $sPageTemplatePath @deprecated since 3.2.1 */
protected $sPageTemplatePath;
/** @var string $sTitle */
protected $sTitle;
@@ -93,6 +99,37 @@ abstract class AbstractBrick
/** @var string $sDeniedProfilesOql */
protected $sDeniedProfilesOql;
/** @var \Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesProviderService Templating provider service for registering default templates paths */
private static TemplatesProviderService $oTemplatesProviderService;
/** @inheritdoc */
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('page', static::TEMPLATES_BASE_PATH . 'layout.html.twig'),
);
}
/**
* @param \Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesProviderService $oTemplateProviderService
*
* @return void
*/
public static function SetTemplatesProviderService(TemplatesProviderService $oTemplateProviderService): void
{
self::$oTemplatesProviderService = $oTemplateProviderService;
}
/**
* Return the templates provider service.
*
* @return \Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesProviderService
*/
protected static function GetTemplatesProviderService(): TemplatesProviderService
{
return self::$oTemplatesProviderService;
}
/**
* Returns all enum values for the data loading modes in an array.
*
@@ -112,7 +149,9 @@ abstract class AbstractBrick
$this->bActive = static::DEFAULT_ACTIVE;
$this->bVisible = static::DEFAULT_VISIBLE;
$this->fRank = static::DEFAULT_RANK;
// BEGIN cleaning 3.2.1 deprecated
$this->sPageTemplatePath = static::DEFAULT_PAGE_TEMPLATE_PATH;
// END cleaning 3.2.1 deprecated
$this->sTitle = static::DEFAULT_TITLE;
$this->sDescription = static::DEFAULT_DESCRIPTION;
$this->sDataLoading = static::DEFAULT_DATA_LOADING;
@@ -176,10 +215,12 @@ abstract class AbstractBrick
* Returns the brick page template path
*
* @return string
*
* @deprecated since 3.2.1 use GetTemplatePath('page') instead
*/
public function GetPageTemplatePath()
{
return $this->sPageTemplatePath;
return $this->GetTemplatePath('page');
}
/**
@@ -323,10 +364,13 @@ abstract class AbstractBrick
* @param string $sPageTemplatePath
*
* @return \Combodo\iTop\Portal\Brick\AbstractBrick
*
* @deprecated since 3.2.1 use SetTemplatePath('page') instead
*/
public function SetPageTemplatePath($sPageTemplatePath)
{
$this->sPageTemplatePath = $sPageTemplatePath;
$this->SetTemplatePath( 'page', $sPageTemplatePath);
return $this;
}
@@ -616,7 +660,7 @@ abstract class AbstractBrick
{
/** @var \Combodo\iTop\DesignElement $oTemplateNode */
$oTemplateNode = $oTemplateNodeList->item(0);
$this->SetPageTemplatePath($oTemplateNode->GetText(static::DEFAULT_PAGE_TEMPLATE_PATH));
$this->SetTemplatePath('page', $oTemplateNode->GetText(static::DEFAULT_PAGE_TEMPLATE_PATH));
}
break;
case 'title':
@@ -659,4 +703,49 @@ abstract class AbstractBrick
return $this;
}
/**
* Override the brick default template path.
* Template is managed by the TemplatesProviderService.
*
* @since 3.2.1
*
* @param string $sTemplateId
* @param string $sTileTemplatePath
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*/
public function SetTemplatePath(string $sTemplateId, string $sTileTemplatePath): AbstractBrick
{
static::GetTemplatesProviderService()->OverrideInstanceTemplatePath($this, $sTemplateId, $sTileTemplatePath);
return $this;
}
/**
* Returns the brick template path.
* Template is managed by the TemplatesProviderService.
*
* @since 3.2.1
*
* @param string $sTemplateId template identifier
*
* @return string template path
*/
public function GetTemplatePath(string $sTemplateId): string
{
return static::GetTemplatesProviderService()->GetProviderInstanceTemplatePath($this, $sTemplateId);
}
/**
* Returns true if this brick template path is overridden.
*
* @since 3.2.1
*
* @param string $sTemplateId template identifier
*
* @return string|null
*/
public function HasInstanceOverriddenTemplate(string $sTemplateId): ?string
{
return static::GetTemplatesProviderService()->HasInstanceOverriddenTemplate($this, $sTemplateId);
}
}

View File

@@ -21,6 +21,8 @@
namespace Combodo\iTop\Portal\Brick;
use Combodo\iTop\DesignElement;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplateDefinitionDto;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesRegister;
use Dict;
use DOMFormatException;
@@ -38,6 +40,8 @@ class AggregatePageBrick extends PortalBrick
// Overloaded constants
const DEFAULT_DECORATION_CLASS_HOME = 'fas fa-tachometer-alt';
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fas fa-tachometer-alt fa-2x';
/** @var string @deprecated since 3.2.1 */
const DEFAULT_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/aggregate-page/layout.html.twig';
// Overloaded variables
@@ -48,6 +52,15 @@ class AggregatePageBrick extends PortalBrick
*/
private $aAggregatePageBricks = array();
/** @inheritdoc */
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
parent::RegisterTemplates($oTemplatesRegister);
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('page', static::TEMPLATES_BASE_PATH . 'aggregate-page/layout.html.twig')
);
}
/**
* AggregatePageBrick constructor.
*/

View File

@@ -19,6 +19,7 @@
namespace Combodo\iTop\Portal\Brick;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesProviderService;
use DOMFormatException;
use Exception;
use UserRights;
@@ -52,10 +53,15 @@ class BrickCollection
* BrickCollection constructor.
*
* @param \ModuleDesign $oModuleDesign
* @param \Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesProviderService $oTemplatesProviderService
*
* @throws \Exception
*
* @since 3.2.1 Added $oTemplatesProviderService parameter
* Important: The service is not directly used, but the injection ensure that the service is initialized.
* Bricks may need to use the service to get the templates.
*/
public function __construct(ModuleDesign $oModuleDesign)
public function __construct(ModuleDesign $oModuleDesign, TemplatesProviderService $oTemplatesProviderService)
{
$this->oModuleDesign = $oModuleDesign;
$this->aAllowedBricks = null;
@@ -196,6 +202,8 @@ class BrickCollection
{
/** @var \Combodo\iTop\Portal\Brick\PortalBrick $oBrick */
$oBrick = new $sBrickClass();
// Load the brick specific properties from its XML definition
$oBrick->LoadFromXml($oBrickNode);
$aBricks[] = $oBrick;

View File

@@ -20,8 +20,10 @@
namespace Combodo\iTop\Portal\Brick;
use DOMFormatException;
use Combodo\iTop\DesignElement;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplateDefinitionDto;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesRegister;
use DOMFormatException;
/**
* Description of BrowseBrick
@@ -32,6 +34,23 @@ use Combodo\iTop\DesignElement;
*/
class BrowseBrick extends PortalBrick
{
/**
* @var string DEFAULT_PAGE_TEMPLATE_PATH
* @deprecated 3.2.1
*/
const DEFAULT_MODE_LIST_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/browse/mode_list.html.twig';
/**
* @var string DEFAULT_MODE_MOSAIC_TEMPLATE_PATH
* @deprecated 3.2.1
*/
const DEFAULT_MODE_MOSAIC_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/browse/mode_mosaic.html.twig';
/**
* @var string DEFAULT_MODE_TREE_TEMPLATE_PATH
* @deprecated 3.2.1
*/
const DEFAULT_MODE_TREE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/browse/mode_tree.html.twig';
/** @var string ENUM_BROWSE_MODE_LIST */
const ENUM_BROWSE_MODE_LIST = 'list';
/** @var string ENUM_BROWSE_MODE_TREE */
@@ -97,6 +116,18 @@ class BrowseBrick extends PortalBrick
/** @var int $iDefaultListLength */
protected $iDefaultListLength;
/** @inheritdoc */
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
parent::RegisterTemplates($oTemplatesRegister);
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('page', static::TEMPLATES_BASE_PATH . 'browse/layout.html.twig'),
TemplateDefinitionDto::Create('page_list', static::TEMPLATES_BASE_PATH . 'browse/mode_list.html.twig'),
TemplateDefinitionDto::Create('page_tree', static::TEMPLATES_BASE_PATH . 'browse/mode_tree.html.twig'),
TemplateDefinitionDto::Create('page_mosaic', static::TEMPLATES_BASE_PATH . 'browse/mode_mosaic.html.twig'),
);
}
/**
* BrowseBrick constructor.
*/
@@ -355,13 +386,8 @@ class BrowseBrick extends PortalBrick
$oTemplateNode = $oModeNode->GetOptionalElement('template');
if (($oTemplateNode !== null) && ($oTemplateNode->GetText() !== null))
{
$sTemplatePath = $oTemplateNode->GetText();
$this->SetTemplatePath('page_'.$sModeId, $oTemplateNode->GetText());
}
else
{
$sTemplatePath = 'itop-portal-base/portal/templates/bricks/browse/mode_'.$sModeId.'.html.twig';
}
$aModeData['template'] = $sTemplatePath;
$this->AddAvailableBrowseMode($sModeId, $aModeData);
}

View File

@@ -20,8 +20,8 @@
namespace Combodo\iTop\Portal\Brick;
use DOMFormatException;
use Combodo\iTop\DesignElement;
use DOMFormatException;
/**
* Description of CreateBrick
@@ -35,8 +35,6 @@ class CreateBrick extends PortalBrick
// Overloaded constants
const DEFAULT_DECORATION_CLASS_HOME = 'fas fa-plus';
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fas fa-plus fa-2x';
const DEFAULT_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/create/modal.html.twig';
/** @var string DEFAULT_CLASS */
const DEFAULT_CLASS = '';

View File

@@ -20,8 +20,10 @@
namespace Combodo\iTop\Portal\Brick;
use DOMFormatException;
use Combodo\iTop\DesignElement;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplateDefinitionDto;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesRegister;
use DOMFormatException;
/**
* Description of FilterBrick
@@ -34,10 +36,12 @@ class FilterBrick extends PortalBrick
{
// Overloaded constants
const DEFAULT_VISIBLE_NAVIGATION_MENU = false;
const DEFAULT_TILE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/filter/tile.html.twig';
/**
* @deprecated 3.2.1
*/
const DEFAULT_TILE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/filter/tile.html.twig';
const DEFAULT_DECORATION_CLASS_HOME = 'fas fa-search';
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fas fa-search fa-2x';
/** @var string DEFAULT_TARGET_BRICK_CLASS */
const DEFAULT_TARGET_BRICK_CLASS = 'Combodo\\iTop\\Portal\\Brick\\BrowseBrick';
/** @var string DEFAULT_SEARCH_PLACEHOLDER_VALUE */
@@ -60,6 +64,15 @@ class FilterBrick extends PortalBrick
/** @var string $sSearchSubmitClass */
protected $sSearchSubmitClass;
/** @inheritdoc */
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
parent::RegisterTemplates($oTemplatesRegister);
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('tile', static::TEMPLATES_BASE_PATH . 'filter/tile.html.twig')
);
}
/**
* FilterBrick constructor.
*/

View File

@@ -20,11 +20,14 @@
namespace Combodo\iTop\Portal\Brick;
use Exception;
use DOMFormatException;
use DBSearch;
use MetaModel;
use Combodo\iTop\DesignElement;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplateDefinitionDto;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesRegister;
use DBSearch;
use DOMFormatException;
use Exception;
use MetaModel;
use ModuleDesign;
class ManageBrick extends PortalBrick
{
@@ -51,16 +54,26 @@ class ManageBrick extends PortalBrick
/** @var string ENUM_DISPLAY_MODE_BAR */
const ENUM_DISPLAY_MODE_BAR = 'bar-chart';
/** @var string ENUM_PAGE_TEMPLATE_PATH_TABLE */
/** @var string ENUM_PAGE_TEMPLATE_PATH_TABLE
* @deprecated since 3.2.1
* */
const ENUM_PAGE_TEMPLATE_PATH_TABLE = 'itop-portal-base/portal/templates/bricks/manage/layout-table.html.twig';
/** @var string ENUM_PAGE_TEMPLATE_PATH_CHART */
/** @var string ENUM_PAGE_TEMPLATE_PATH_CHART
* @deprecated since 3.2.1
* */
const ENUM_PAGE_TEMPLATE_PATH_CHART = 'itop-portal-base/portal/templates/bricks/manage/layout-chart.html.twig';
// Overloaded constants
/** Overloaded constants */
const DEFAULT_DECORATION_CLASS_HOME = 'fas fa-pen-square';
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fas fa-pen-square fa-2x';
/**
* @deprecated 3.2.1
*/
const DEFAULT_PAGE_TEMPLATE_PATH = self::ENUM_PAGE_TEMPLATE_PATH_TABLE;
const DEFAULT_DATA_LOADING = self::ENUM_DATA_LOADING_LAZY;
/**
* @deprecated 3.2.1
*/
const DEFAULT_TILE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/manage/tile-default.html.twig';
const DEFAULT_TILE_CONTROLLER_ACTION = 'Combodo\\iTop\\Portal\\Controller\\ManageBrickController::TileAction';
@@ -84,20 +97,24 @@ class ManageBrick extends PortalBrick
const DEFAULT_GROUP_SHOW_OTHERS = true;
/** @var array $aDisplayModes */
static $aDisplayModes = array(
public static array $aDisplayModes = array(
self::ENUM_DISPLAY_MODE_LIST,
self::ENUM_DISPLAY_MODE_PIE,
self::ENUM_DISPLAY_MODE_BAR,
);
/** @var array $aTileModes */
public static $aTileModes = array(
public static array $aTileModes = array(
self::ENUM_TILE_MODE_TEXT,
self::ENUM_TILE_MODE_BADGE,
self::ENUM_TILE_MODE_PIE,
self::ENUM_TILE_MODE_BAR,
self::ENUM_TILE_MODE_TOP,
);
/** @var array $aPresentationData */
/** @var array $aPresentationData
* @deprecated since 3.2.1
*/
public static $aPresentationData = array(
self::ENUM_TILE_MODE_BADGE => array(
'decorationCssClass' => 'fas fa-id-card fa-2x',
@@ -136,6 +153,38 @@ class ManageBrick extends PortalBrick
),
);
/** @var array $aDefaultTileData */
private static array $aDefaultTileData = [
self::ENUM_TILE_MODE_BADGE => [
'decorationCssClass' => 'fas fa-id-card fa-2x',
],
self::ENUM_TILE_MODE_TOP => [
'decorationCssClass' => 'fas fa-list-ol fa-2x',
],
self::ENUM_TILE_MODE_PIE => [
'decorationCssClass' => 'fas fa-chart-pie fa-2x',
],
self::ENUM_TILE_MODE_TEXT => [
'decorationCssClass' => 'fas fa-pen-square fa-2x',
],
self::ENUM_TILE_MODE_BAR => [
'decorationCssClass' => 'fas fa-chart-bar fa-2x',
],
];
/** @var array $aDefaultLayoutData */
private static array $aDefaultLayoutData = [
self::ENUM_DISPLAY_MODE_LIST => [
'need_details' => true,
],
self::ENUM_DISPLAY_MODE_PIE => [
'need_details' => false,
],
self::ENUM_DISPLAY_MODE_BAR => [
'need_details' => false,
],
];
// Overloaded variables
public static $sRouteName = 'p_manage_brick';
@@ -164,48 +213,21 @@ class ManageBrick extends PortalBrick
/** @var int $iDefaultListLength */
protected $iDefaultListLength;
/**
* Returns true if the $sDisplayMode need objects details for rendering.
*
* @param string $sDisplayMode
*
* @return bool
*/
static public function AreDetailsNeededForDisplayMode($sDisplayMode)
/** @inheritdoc */
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
$bNeedDetails = false;
foreach (static::$aPresentationData as $aData)
{
if ($aData['layoutDisplayMode'] === $sDisplayMode)
{
$bNeedDetails = $aData['need_details'];
break;
}
}
return $bNeedDetails;
}
/**
* Returns the page template path for the $sDisplayMode
*
* @param string $sDisplayMode
*
* @return string
*/
static public function GetPageTemplateFromDisplayMode($sDisplayMode)
{
$sTemplate = static::DEFAULT_PAGE_TEMPLATE_PATH;
foreach (static::$aPresentationData as $aData)
{
if ($aData['layoutDisplayMode'] === $sDisplayMode)
{
$sTemplate = $aData['layoutTemplate'];
break;
}
}
return $sTemplate;
parent::RegisterTemplates($oTemplatesRegister);
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('tile', static::TEMPLATES_BASE_PATH . 'manage/tile-default.html.twig'),
TemplateDefinitionDto::Create('tile_badge', static::TEMPLATES_BASE_PATH. 'manage/tile-badge.html.twig'),
TemplateDefinitionDto::Create('tile_chart', static::TEMPLATES_BASE_PATH . 'manage/tile-chart.html.twig'),
TemplateDefinitionDto::Create('tile_top_list', static::TEMPLATES_BASE_PATH . 'manage/tile-top-list.html.twig'),
TemplateDefinitionDto::Create('page', static::TEMPLATES_BASE_PATH . 'manage/layout.html.twig'),
TemplateDefinitionDto::Create('page_table', static::TEMPLATES_BASE_PATH . 'manage/layout-table.html.twig'),
TemplateDefinitionDto::Create('page_chart', static::TEMPLATES_BASE_PATH . 'manage/layout-chart.html.twig'),
TemplateDefinitionDto::Create('mode_chart_bar', static::TEMPLATES_BASE_PATH . 'manage/mode-bar-chart.html.twig', true, self::ENUM_DISPLAY_MODE_BAR),
TemplateDefinitionDto::Create('mode_chart_pie', static::TEMPLATES_BASE_PATH . 'manage/mode-pie-chart.html.twig', true,self::ENUM_DISPLAY_MODE_PIE),
);
}
/**
@@ -232,6 +254,101 @@ class ManageBrick extends PortalBrick
$this->AddGrouping('areas', array('attribute' => 'finalclass'));
}
/**
* Returns true if the $sDisplayMode need objects details for rendering.
*
* @deprecated since 3.2.1
*
* @param string $sDisplayMode
*
* @return bool
*/
static public function AreDetailsNeededForDisplayMode($sDisplayMode)
{
$bNeedDetails = false;
foreach (static::$aPresentationData as $aData)
{
if ($aData['layoutDisplayMode'] === $sDisplayMode)
{
$bNeedDetails = $aData['need_details'];
break;
}
}
return $bNeedDetails;
}
/**
* Returns if the $sLayoutMode need objects details for rendering.
*
* @since 3.2.1
*
* @param string $sLayoutMode
*
* @return bool
*/
public function IsDetailsNeeded(string $sLayoutMode): bool
{
return static::$aDefaultLayoutData[$sLayoutMode]['need_details'];
}
/**
* Returns the page template path for the $sDisplayMode
*
* @deprecated since 3.2.1
*
* @param string $sDisplayMode
* @return string
*/
static public function GetPageTemplateFromDisplayMode($sDisplayMode)
{
$sTemplate = static::DEFAULT_PAGE_TEMPLATE_PATH;
foreach (static::$aPresentationData as $aData)
{
if ($aData['layoutDisplayMode'] === $sDisplayMode)
{
$sTemplate = $aData['layoutTemplate'];
break;
}
}
return $sTemplate;
}
/**
* Returns the page template path for the $sDisplayMode
*
* @since 3.2.1
*
* @param string $sDisplayMode
*
* @return string
*/
public function GetPageTemplate(string $sDisplayMode): string
{
return match ($sDisplayMode) {
self::ENUM_DISPLAY_MODE_BAR, self::ENUM_DISPLAY_MODE_PIE => $this->GetTemplatePath('page_chart'),
default => $this->GetTemplatePath('page_table'),
};
}
/**
* Returns the page template path for the $sDisplayMode
* @since 3.2.1
*
* @return string
*/
public function GetTileTemplate(): string
{
return match ($this->GetTileMode()) {
self::ENUM_TILE_MODE_BADGE => $this->GetTemplatePath('tile_badge'),
self::ENUM_TILE_MODE_PIE, self::ENUM_TILE_MODE_BAR => $this->GetTemplatePath('tile_chart'),
self::ENUM_TILE_MODE_TOP => $this->GetTemplatePath('tile_top_list'),
default => $this->GetTemplatePath('tile'),
};
}
/**
* Returns the brick oql
*
@@ -326,10 +443,24 @@ class ManageBrick extends PortalBrick
return $this->sTileMode;
}
/**
* @deprecated since 3.2.1
*/
public function GetDecorationCssClass()
{
return static::$aPresentationData[$this->sTileMode]['decorationCssClass'];
}
/**
* @since 3.2.1
*
* @return mixed|string
*/
public function GetDecoration()
{
return static::$aDefaultTileData[$this->sTileMode]['decorationCssClass'];
}
/**
* Sets the tile mode (display)
*
@@ -345,6 +476,8 @@ class ManageBrick extends PortalBrick
}
/**
* @deprecated since 3.2.1
*
* @param string $sTileMode
*
* @return string[] parameters for specified type, default parameters if type is invalid
@@ -466,7 +599,7 @@ class ManageBrick extends PortalBrick
$this->iDefaultListLength = $iDefaultListLength;
return $this;
}
/**
* Adds a grouping.
*
@@ -781,10 +914,11 @@ class ManageBrick extends PortalBrick
case 'tile';
$this->SetTileMode($oDisplayNode->GetText(static::DEFAULT_TILE_MODE));
$aTileParametersForType = $this->GetPresentationDataForTileMode($this->sTileMode);
$this->SetTileTemplatePath($aTileParametersForType['tileTemplate']);
$this->SetPageTemplatePath($aTileParametersForType['layoutTemplate']);
if($this->sDecorationClassHome === static::DEFAULT_DECORATION_CLASS_HOME){
$this->sDecorationClassHome = static::$aDefaultTileData[$this->GetTileMode()]['decorationCssClass'];
$this->SetDecorationClassNavigationMenu(static::$aDefaultTileData[$this->GetTileMode()]['decorationCssClass']);
$this->SetDecorationClassHome(static::$aDefaultTileData[$this->GetTileMode()]['decorationCssClass']);
}
break;
}
}
@@ -918,6 +1052,19 @@ class ManageBrick extends PortalBrick
}
}
break;
case 'templates':
$aTemplatesIds = static::GetTemplatesProviderService()->GetRegister()->GetProviderTemplatesIds(self::class);
/** @var TemplateDefinitionDto $oTemplateDefinition */
foreach ($aTemplatesIds as $sTemplateId) {
$oTemplateNodeList = $oBrickSubNode->GetNodes('template[@id='.ModuleDesign::XPathQuote($sTemplateId).']');
if ($oTemplateNodeList->length > 0) {
/** @var \Combodo\iTop\DesignElement $oTemplateNode */
$oTemplateNode = $oTemplateNodeList->item(0);
$this->SetTemplatePath($sTemplateId, $oTemplateNode->GetText(static::DEFAULT_TILE_TEMPLATE_PATH));
}
}
break;
}
}
@@ -965,10 +1112,10 @@ class ManageBrick extends PortalBrick
// Checking the navigation icon
$sDecorationClassNavigationMenu = $this->GetDecorationClassNavigationMenu();
if (empty($sDecorationClassNavigationMenu) && isset(static::$aPresentationData[$this->sTileMode]))
if (empty($sDecorationClassNavigationMenu) && isset(static::$aDefaultTileData[$this->sTileMode]))
{
/** @var string $sDecorationClassNavigationMenu */
$sDecorationClassNavigationMenu = static::$aPresentationData[$this->sTileMode]['decorationCssClass'];
$sDecorationClassNavigationMenu = static::$aDefaultTileData[$this->sTileMode]['decorationCssClass'];
if (!empty($sDecorationClassNavigationMenu))
{
$this->SetDecorationClassNavigationMenu($sDecorationClassNavigationMenu);

View File

@@ -20,9 +20,11 @@
namespace Combodo\iTop\Portal\Brick;
use Combodo\iTop\DesignElement;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplateDefinitionDto;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesRegister;
use DOMFormatException;
use ModuleDesign;
use Combodo\iTop\DesignElement;
/**
* Description of PortalBrick
@@ -70,6 +72,8 @@ abstract class PortalBrick extends AbstractBrick
/** @var int $iWidth */
protected $iWidth;
/** @var bool width in pixel flag */
public bool $bIsWidthPixel = false;
/** @var int $iHeight */
protected $iHeight;
/** @var bool $bModal */
@@ -82,7 +86,7 @@ abstract class PortalBrick extends AbstractBrick
protected $sDecorationClassHome;
/** @var string $sDecorationClassNavigationMenu */
protected $sDecorationClassNavigationMenu;
/** @var string $sTileTemplatePath */
/** @var string $sTileTemplatePath @deprecated since 3.2.1 */
protected $sTileTemplatePath;
/** @var string|null $sTileControllerAction */
protected $sTileControllerAction;
@@ -99,6 +103,17 @@ abstract class PortalBrick extends AbstractBrick
/** @var string $sTitleNavigationMenu */
protected $sTitleNavigationMenu;
/** @inheritdoc */
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
parent::RegisterTemplates($oTemplatesRegister);
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('tile', static::TEMPLATES_BASE_PATH . 'tile.html.twig'),
);
}
/**
* @return string|null
*/
@@ -121,7 +136,9 @@ abstract class PortalBrick extends AbstractBrick
$this->bVisibleNavigationMenu = static::DEFAULT_VISIBLE_NAVIGATION_MENU;
$this->sDecorationClassHome = static::DEFAULT_DECORATION_CLASS_HOME;
$this->sDecorationClassNavigationMenu = static::DEFAULT_DECORATION_CLASS_NAVIGATION_MENU;
// BEGIN cleaning 3.2.1 deprecated
$this->sTileTemplatePath = static::DEFAULT_TILE_TEMPLATE_PATH;
// END cleaning 3.2.1 deprecated
$this->sTileControllerAction = static::DEFAULT_TILE_CONTROLLER_ACTION;
$this->sOpeningTarget = static::DEFAULT_OPENING_TARGET;
}
@@ -250,10 +267,12 @@ abstract class PortalBrick extends AbstractBrick
* Returns the brick tile template path
*
* @return string
*
* @deprecated since 3.2.1 use GetTemplatePath('tile') instead
*/
public function GetTileTemplatePath()
{
return $this->sTileTemplatePath;
return $this->GetTemplatePath('tile');
}
/**
@@ -426,10 +445,13 @@ abstract class PortalBrick extends AbstractBrick
* @param string $sTileTemplatePath
*
* @return \Combodo\iTop\Portal\Brick\PortalBrick
*
* @deprecated since 3.2.1 use SetTemplatePath('tile') instead
*/
public function SetTileTemplatePath($sTileTemplatePath)
{
$this->sTileTemplatePath = $sTileTemplatePath;
$this->SetTemplatePath('tile', $sTileTemplatePath);
return $this;
}
@@ -483,7 +505,9 @@ abstract class PortalBrick extends AbstractBrick
switch ($oBrickSubNode->nodeName)
{
case 'width':
$this->SetWidth((int)$oBrickSubNode->GetText(static::DEFAULT_WIDTH));
$sWidth = $oBrickSubNode->GetText(static::DEFAULT_WIDTH);
$this->bIsWidthPixel = str_contains($sWidth, 'px');
$this->SetWidth((int)$sWidth);
break;
case 'height':
@@ -526,7 +550,7 @@ abstract class PortalBrick extends AbstractBrick
{
/** @var \Combodo\iTop\DesignElement $oTemplateNode */
$oTemplateNode = $oTemplateNodeList->item(0);
$this->SetTileTemplatePath($oTemplateNode->GetText(static::DEFAULT_TILE_TEMPLATE_PATH));
$this->SetTemplatePath('tile', $oTemplateNode->GetText(static::DEFAULT_TILE_TEMPLATE_PATH));
}
break;

View File

@@ -20,6 +20,8 @@
namespace Combodo\iTop\Portal\Brick;
use Combodo\iTop\DesignElement;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplateDefinitionDto;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesRegister;
use DOMFormatException;
/**
@@ -32,14 +34,10 @@ use DOMFormatException;
class UserProfileBrick extends PortalBrick
{
// Overloaded constants
const DEFAULT_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/user-profile/layout.html.twig';
const DEFAULT_TILE_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/user-profile/tile.html.twig';
const DEFAULT_VISIBLE_NAVIGATION_MENU = false;
const DEFAULT_VISIBLE_HOME = false;
const DEFAUT_TITLE = 'Brick:Portal:UserProfile:Title';
const DEFAULT_DECORATION_CLASS_HOME = 'glyphicon glyphicon-user';
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'glyphicon glyphicon-user';
/** @var bool DEFAULT_SHOW_PICTURE_FORM */
const DEFAULT_SHOW_PICTURE_FORM = true;
/** @var bool DEFAULT_SHOW_PREFERENCES_FORM */
@@ -59,6 +57,17 @@ class UserProfileBrick extends PortalBrick
/** @var bool $bShowPasswordForm */
protected $bShowPasswordForm;
/** @inheritdoc */
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
parent::RegisterTemplates($oTemplatesRegister);
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('page', static::TEMPLATES_BASE_PATH . 'user-profile/layout.html.twig'),
TemplateDefinitionDto::Create('user_info', static::TEMPLATES_BASE_PATH.'user-profile/user_info.html.twig'),
TemplateDefinitionDto::Create('user_info_ready_js', static::TEMPLATES_BASE_PATH.'user-profile/user_info.ready.js.twig'),
);
}
/**
* UserProfileBrick constructor.
*/

View File

@@ -20,7 +20,11 @@
namespace Combodo\iTop\Portal\Controller;
use \Symfony\Bundle\FrameworkBundle\Controller\AbstractController as SymfonyAbstractController;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesProviderInterface;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplateDefinitionDto;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesProviderService;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesRegister;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController as SymfonyAbstractController;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Contracts\Service\Attribute\Required;
@@ -31,8 +35,23 @@ use Symfony\Contracts\Service\Attribute\Required;
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 2.3.0
*/
abstract class AbstractController extends SymfonyAbstractController
abstract class AbstractController extends SymfonyAbstractController implements TemplatesProviderInterface
{
const TEMPLATES_BASE_PATH = 'itop-portal-base/portal/templates/';
/** @inheritdoc */
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('page', static::TEMPLATES_BASE_PATH . 'layout.html.twig'),
TemplateDefinitionDto::Create('modal', static::TEMPLATES_BASE_PATH . 'modal/layout.html.twig'),
TemplateDefinitionDto::Create('loader', static::TEMPLATES_BASE_PATH.'helpers/loader.html.twig'),
TemplateDefinitionDto::Create('tagset_clic_handler_js', static::TEMPLATES_BASE_PATH.'helpers/tagset_clic_handler.js.twig'),
TemplateDefinitionDto::Create('session_message', static::TEMPLATES_BASE_PATH.'helpers/session_messages/session_message.html.twig'),
TemplateDefinitionDto::Create('session_messages', static::TEMPLATES_BASE_PATH.'helpers/session_messages/session_messages.html.twig'),
);
}
/**
* @var \Symfony\Component\Routing\RouterInterface symfony router
*
@@ -46,6 +65,25 @@ abstract class AbstractController extends SymfonyAbstractController
$this->oRouter = $oRouter;
}
/** @var TemplatesProviderService templates provider service */
private TemplatesProviderService $oTemplatesService;
#[Required]
public function SetTemplatesService(TemplatesProviderService $oTemplatesService): void
{
$this->oTemplatesService = $oTemplatesService;
}
/**
* Return the templates provider service.
*
* @return \Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesProviderService
*/
protected function GetTemplatesProviderService(): TemplatesProviderService
{
return $this->oTemplatesService;
}
/**
* Unlike {@see \Symfony\Bundle\FrameworkBundle\Controller\ControllerTrait::redirectToRoute()}, this method directly calls the route controller without creating a redirection client side
*
@@ -104,4 +142,33 @@ abstract class AbstractController extends SymfonyAbstractController
return $aRouteDefaults['_controller'];
}
/**
* Returns the controller template path
*
* @since 3.2.1
*
* @param string $sTemplateId
*
* @return string
*/
public function GetTemplatePath(string $sTemplateId): string
{
return static::GetTemplatesProviderService()->GetProviderInstanceTemplatePath($this, $sTemplateId);
}
/**
* Sets the brick template path
*
* @since 3.2.1
* @param string $sTemplateId
* @param string $sTileTemplatePath
*
* @return \Combodo\iTop\Portal\Controller\AbstractController
*/
public function SetTemplatePath(string $sTemplateId, string $sTileTemplatePath): AbstractController
{
static::GetTemplatesProviderService()->OverrideInstanceTemplatePath($this, $sTemplateId, $sTileTemplatePath);
return $this;
}
}

View File

@@ -75,7 +75,7 @@ class AggregatePageBrickController extends BrickController
$aTilesRendering = $this->GetBricksTileRendering($oRequest, $aAggregatePageBricks);
$sLayoutTemplate = $oBrick->GetPageTemplatePath();
$sLayoutTemplate = $oBrick->GetTemplatePath('page');
$aData = array(
'oBrick' => $oBrick,
'aggregatepage_bricks' => $aAggregatePageBricks,

View File

@@ -495,13 +495,13 @@ class BrowseBrickController extends BrickController
// - Create a template for that browse mode,
// - Add the mode to those available in the brick configuration,
// - Create a router and add a route for the new browse mode
if ($oBrick->GetPageTemplatePath() !== null)
if ($oBrick->HasInstanceOverriddenTemplate('page'))
{
$sTemplatePath = $oBrick->GetPageTemplatePath();
$sTemplatePath = $oBrick->GetTemplatePath('page');
}
else
{
$sTemplatePath = $aBrowseModes[$sBrowseMode]['template'];
$sTemplatePath = $oBrick->GetTemplatePath('page_' .$sBrowseMode);
}
$oResponse = $this->render($sTemplatePath, $aData);
}

View File

@@ -23,7 +23,6 @@ namespace Combodo\iTop\Portal\Controller;
use Combodo\iTop\Portal\Brick\BrickCollection;
use Combodo\iTop\Portal\Helper\ContextManipulatorHelper;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* Class CreateBrickController

View File

@@ -21,6 +21,8 @@
namespace Combodo\iTop\Portal\Controller;
use Combodo\iTop\Portal\Brick\BrickCollection;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplateDefinitionDto;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesRegister;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -33,6 +35,15 @@ use Symfony\Component\HttpFoundation\Response;
*/
class DefaultController extends AbstractController
{
/** @inheritdoc */
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
parent::RegisterTemplates($oTemplatesRegister);
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('home', static::TEMPLATES_BASE_PATH . 'home/layout.html.twig'),
);
}
/**
* @param \Symfony\Component\HttpFoundation\Request $oRequest
* @param \Combodo\iTop\Portal\Brick\BrickCollection $oBricksCollection
@@ -72,7 +83,7 @@ class DefaultController extends AbstractController
}
// Home page template
$sTemplatePath = $this->getParameter('combodo.portal.instance.conf')['properties']['templates']['home'];
$sTemplatePath = $this->GetTemplatePath('home');
return $this->render($sTemplatePath, $aData);
}

View File

@@ -40,6 +40,8 @@ use Combodo\iTop\Portal\Helper\RequestManipulatorHelper;
use Combodo\iTop\Portal\Helper\ScopeValidatorHelper;
use Combodo\iTop\Portal\Helper\SecurityHelper;
use Combodo\iTop\Portal\Routing\UrlGenerator;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplateDefinitionDto;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesRegister;
use DBObject;
use DBObjectSet;
use DBSearch;
@@ -70,8 +72,20 @@ use utils;
*/
class ManageBrickController extends BrickController
{
/** @var string EXCEL_EXPORT_TEMPLATE_PATH */
/**
* @var string EXCEL_EXPORT_TEMPLATE_PATH
* @deprecated since 3.2.1
*/
const EXCEL_EXPORT_TEMPLATE_PATH = 'itop-portal-base/portal/templates/bricks/manage/popup-export-excel.html.twig';
/** @inheritdoc */
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
parent::RegisterTemplates($oTemplatesRegister);
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('modal_export_excel', static::TEMPLATES_BASE_PATH . 'bricks/manage/popup-export-excel.html.twig'),
);
}
/**
* @param \Combodo\iTop\Portal\Brick\BrickCollection $oBrickCollection
@@ -121,7 +135,7 @@ class ManageBrickController extends BrickController
$sDisplayMode = $oBrick->GetDefaultDisplayMode();
}
$aData = $this->GetData($oRequest, $sBrickId, $sGroupingTab, $oBrick::AreDetailsNeededForDisplayMode($sDisplayMode));
$aData = $this->GetData($oRequest, $sBrickId, $sGroupingTab, $oBrick->IsDetailsNeeded($sDisplayMode));
$aExportFields = $oBrick->GetExportFields();
$aData = $aData + array(
@@ -135,7 +149,7 @@ class ManageBrickController extends BrickController
}
else
{
$sLayoutTemplate = $oBrick::GetPageTemplateFromDisplayMode($sDisplayMode);
$sLayoutTemplate = $oBrick->GetPageTemplate($sDisplayMode);
$oResponse = $this->render($sLayoutTemplate, $aData);
}
@@ -167,7 +181,7 @@ class ManageBrickController extends BrickController
$aData = array();
}
return $this->render($oBrick->GetTileTemplatePath(), $aData);
return $this->render($oBrick->GetTileTemplate(), $aData);
}
/**
@@ -281,7 +295,7 @@ class ManageBrickController extends BrickController
'sWikiUrl' => 'https://www.itophub.io/wiki/page?id='.utils::GetItopVersionWikiSyntax().'%3Auser%3Alists#excel_export',
);
return $this->render(static::EXCEL_EXPORT_TEMPLATE_PATH, $aData);
return $this->render($this->GetTemplatePath('modal_export_excel'), $aData);
}
/**

View File

@@ -37,6 +37,8 @@ use Combodo\iTop\Portal\Helper\RequestManipulatorHelper;
use Combodo\iTop\Portal\Helper\ScopeValidatorHelper;
use Combodo\iTop\Portal\Helper\SecurityHelper;
use Combodo\iTop\Portal\Routing\UrlGenerator;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplateDefinitionDto;
use Combodo\iTop\Portal\Service\TemplatesProvider\TemplatesRegister;
use Combodo\iTop\Renderer\Bootstrap\FieldRenderer\BsLinkedSetFieldRenderer;
use DBObject;
use DBObjectSearch;
@@ -74,6 +76,24 @@ class ObjectController extends BrickController
const DEFAULT_PAGE_NUMBER = 1;
const DEFAULT_LIST_LENGTH = 10;
/** @inheritdoc */
public static function RegisterTemplates(TemplatesRegister $oTemplatesRegister): void
{
parent::RegisterTemplates($oTemplatesRegister);
$oTemplatesRegister->RegisterTemplates(self::class,
TemplateDefinitionDto::Create('page', static::TEMPLATES_BASE_PATH. 'bricks/object/layout.html.twig'),
TemplateDefinitionDto::Create('modal', static::TEMPLATES_BASE_PATH. 'bricks/object/modal.html.twig'),
TemplateDefinitionDto::Create('mode_create', static::TEMPLATES_BASE_PATH.'bricks/object/mode_create.html.twig', true, 'create'),
TemplateDefinitionDto::Create('mode_edit', static::TEMPLATES_BASE_PATH.'bricks/object/mode_edit.html.twig', true, 'edit'),
TemplateDefinitionDto::Create('mode_search_hierarchy', static::TEMPLATES_BASE_PATH.'bricks/object/mode_search_hierarchy.html.twig', true, 'search_hierarchy'),
TemplateDefinitionDto::Create('mode_search_regular', static::TEMPLATES_BASE_PATH.'bricks/object/mode_search_regular.html.twig', true, 'search_regular'),
TemplateDefinitionDto::Create('mode_view', static::TEMPLATES_BASE_PATH.'bricks/object/mode_view.html.twig', true, 'view'),
TemplateDefinitionDto::Create('mode_apply_stimulus', static::TEMPLATES_BASE_PATH.'bricks/object/mode_apply_stimulus.html.twig', true, 'apply_stimulus'),
TemplateDefinitionDto::Create('mode_loader', static::TEMPLATES_BASE_PATH.'modal/mode_loader.html.twig'),
TemplateDefinitionDto::Create('plugins_buttons', static::TEMPLATES_BASE_PATH.'bricks/object/plugins_buttons.html.twig'),
);
}
/**
* @param \Combodo\iTop\Portal\Helper\SecurityHelper $oSecurityHelper
* @param \Combodo\iTop\Portal\Helper\ScopeValidatorHelper $oScopeValidatorHelper
@@ -82,8 +102,11 @@ class ObjectController extends BrickController
* @param \Combodo\iTop\Portal\Brick\BrickCollection $oBrickCollection
* @param \Combodo\iTop\Portal\Helper\ObjectFormHandlerHelper $oObjectFormHandlerHelper
* @param \Combodo\iTop\Portal\Helper\NavigationRuleHelper $oNavigationRuleHelper
* @param \Combodo\iTop\Portal\Helper\ContextManipulatorHelper $oContextManipulatorHelper
* @param array $aCombodoPortalInstanceConf
*
* @since 3.2.0 N°6933
* @since 3.2.1 Added $aCombodoPortalInstanceConf parameter
*/
public function __construct(
protected SecurityHelper $oSecurityHelper,
@@ -93,10 +116,11 @@ class ObjectController extends BrickController
protected BrickCollection $oBrickCollection,
protected ObjectFormHandlerHelper $oObjectFormHandlerHelper,
protected NavigationRuleHelper $oNavigationRuleHelper,
protected ContextManipulatorHelper $oContextManipulatorHelper
protected ContextManipulatorHelper $oContextManipulatorHelper,
protected array $aCombodoPortalInstanceConf = []
)
{
}
/**
@@ -232,7 +256,7 @@ class ObjectController extends BrickController
if ($oRequest->isXmlHttpRequest()) {
// We have to check whether the 'operation' parameter is defined or not in order to know if the form is required via ajax (to be displayed as a modal dialog) or if it's a lifecycle call from a existing form.
if (empty($sOperation)) {
$oResponse = $this->render('itop-portal-base/portal/templates/bricks/object/modal.html.twig', $aData);
$oResponse = $this->render($this->GetTemplatePath('modal'), $aData);
} else {
$oResponse = new JsonResponse($aData);
}
@@ -246,7 +270,7 @@ class ObjectController extends BrickController
}
}
$aData['sPageTitle'] = $aData['form']['title'];
$oResponse = $this->render('itop-portal-base/portal/templates/bricks/object/layout.html.twig', $aData);
$oResponse = $this->render($this->GetTemplatePath('page'), $aData);
}
return $oResponse;
@@ -307,7 +331,7 @@ class ObjectController extends BrickController
// We have to check whether the 'operation' parameter is defined or not in order to know if the form is required via ajax (to be displayed as a modal dialog) or if it's a lifecycle call from a existing form.
if (empty($sOperation))
{
$oResponse = $this->render('itop-portal-base/portal/templates/bricks/object/modal.html.twig', $aData);
$oResponse = $this->render($this->GetTemplatePath('modal'), $aData);
}
else
{
@@ -327,7 +351,7 @@ class ObjectController extends BrickController
}
}
$aData['sPageTitle'] = $aData['form']['title'];
$oResponse = $this->render('itop-portal-base/portal/templates/bricks/object/layout.html.twig', $aData);
$oResponse = $this->render($this->GetTemplatePath('page'), $aData);
}
return $oResponse;
@@ -534,11 +558,11 @@ class ObjectController extends BrickController
// We have to check whether the 'operation' parameter is defined or not in order to know if the form is required via ajax (to be displayed as a modal dialog) or if it's a lifecycle call from a existing form.
if (empty($sOperation))
{
$oResponse = $this->render('itop-portal-base/portal/templates/bricks/object/modal.html.twig', $aData);
$oResponse = $this->render($this->GetTemplatePath('modal'), $aData);
}
elseif ($sOperation === 'redirect')
{
$oResponse = $this->render('itop-portal-base/portal/templates/modal/mode_loader.html.twig', $aData);
$oResponse = $this->render($this->GetTemplatePath('mode_loader'), $aData);
}
else
{
@@ -547,7 +571,7 @@ class ObjectController extends BrickController
}
else
{
$oResponse = $this->render('itop-portal-base/portal/templates/bricks/object/layout.html.twig', $aData);
$oResponse = $this->render($this->GetTemplatePath('page'), $aData);
}
return $oResponse;
@@ -1011,12 +1035,12 @@ class ObjectController extends BrickController
if ($oRequest->isXmlHttpRequest())
{
$oResponse = $this->render('itop-portal-base/portal/templates/bricks/object/modal.html.twig', $aData);
$oResponse = $this->render($this->GetTemplatePath('modal'), $aData);
}
else
{
//throw new HttpException(Response::HTTP_NOT_FOUND, Dict::S('UI:ObjectDoesNotExist'));
$oResponse = $this->render('itop-portal-base/portal/templates/bricks/object/layout.html.twig', $aData);
$oResponse = $this->render($this->GetTemplatePath('page'), $aData);
}
}
else
@@ -1299,6 +1323,11 @@ class ObjectController extends BrickController
$bIgnoreSilos = $this->oScopeValidatorHelper->IsAllDataAllowedForScope(UserRights::ListProfiles(), $sObjectClass);
$aParams = array('objects_id' => $aObjectIds);
$oSearch = DBObjectSearch::FromOQL("SELECT $sObjectClass WHERE id IN (:objects_id)");
if (!$this->oScopeValidatorHelper->AddScopeToQuery($oSearch, $sObjectClass)
) {
IssueLog::Warning(__METHOD__.' at line '.__LINE__.' : User #'.UserRights::GetUserId().' not allowed to read '.$sObjectClass.' object.');
throw new HttpException(Response::HTTP_NOT_FOUND, Dict::S('UI:ObjectDoesNotExist'));
}
if ($bIgnoreSilos === true) {
$oSearch->AllowAllData();
}
@@ -1349,7 +1378,10 @@ class ObjectController extends BrickController
$aObjectAttCodes = $this->oRequestManipulatorHelper->ReadParam('aObjectAttCodes', array(), FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY);
$aLinkAttCodes = $this->oRequestManipulatorHelper->ReadParam('aLinkAttCodes', array(), FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY);
$sDateTimePickerWidgetParent = $this->oRequestManipulatorHelper->ReadParam('sDateTimePickerWidgetParent', array(), FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY);
if (!MetaModel::IsLinkClass($sLinkClass)) {
IssueLog::Warning(__METHOD__.' at line '.__LINE__.' : User #'.UserRights::GetUserId().' asked for wrong lnk class '.$sLinkClass);
throw new HttpException(Response::HTTP_NOT_FOUND, Dict::S('UI:ObjectDoesNotExist'));
}
if (empty($sObjectClass) || empty($aObjectIds) || empty($aObjectAttCodes)) {
IssueLog::Info(__METHOD__.' at line '.__LINE__.' : sObjectClass, aObjectIds and aObjectAttCodes expected, "'.$sObjectClass.'", "'.implode('/',
$aObjectIds).'" given.');
@@ -1360,6 +1392,10 @@ class ObjectController extends BrickController
$bIgnoreSilos = $this->oScopeValidatorHelper->IsAllDataAllowedForScope(UserRights::ListProfiles(), $sObjectClass);
$aParams = array('objects_id' => $aObjectIds);
$oSearch = DBObjectSearch::FromOQL("SELECT $sObjectClass WHERE id IN (:objects_id)");
if (!$this->oScopeValidatorHelper->AddScopeToQuery($oSearch, $sObjectClass)) {
IssueLog::Warning(__METHOD__.' at line '.__LINE__.' : User #'.UserRights::GetUserId().' not allowed to read '.$sObjectClass.' object.');
throw new HttpException(Response::HTTP_NOT_FOUND, Dict::S('UI:ObjectDoesNotExist'));
}
if ($bIgnoreSilos === true)
{
$oSearch->AllowAllData();
@@ -1378,10 +1414,35 @@ class ObjectController extends BrickController
// Prepare link data
$aObjectData = $this->PrepareObjectInformation($oObject, $aObjectAttCodes);
// New link object (needed for renderers)
$oNewLink = new $sLinkClass();
$aAttCodes = MetaModel::GetAttributesList($sLinkClass, ['AttributeExternalKey']);
$sAttCodeToObject = '';
foreach ($aAttCodes as $sAttCode) {
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
/** @var \AttributeExternalKey $oAttDef */
if ($oAttDef->GetTargetClass() === $sObjectClass) {
$sAttCodeToObject = $sAttCode;
}
}
if ($sAttCodeToObject === '') {
IssueLog::Warning(__METHOD__.' at line '.__LINE__.' : User #'.UserRights::GetUserId().' asked for incoherent lnk class '.$sLinkClass.' with object class '.$sObjectClass);
throw new HttpException(Response::HTTP_NOT_FOUND, Dict::S('UI:ObjectDoesNotExist'));
}
$oNewLink = MetaModel::NewObject($sLinkClass, [
$sAttCodeToObject => $oObject->GetKey(), // so later placeholders in filters will be applied on external keys on the same link
]);
foreach ($aLinkAttCodes as $sAttCode) {
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
/** @var \Combodo\iTop\Form\Field\SelectObjectField $oField */
$oField = $oAttDef->MakeFormField($oNewLink);
if ($oAttDef::GetFormFieldClass() === '\\Combodo\\iTop\\Form\\Field\\SelectObjectField') {
$oFieldSearch = $oField->GetSearch();
$sFieldClass = $oFieldSearch->GetClass();
if ($this->oScopeValidatorHelper->AddScopeToQuery($oFieldSearch, $sFieldClass)){
$oField->SetSearch($oFieldSearch);
} else {
$oField->SetSearch(DBObjectSearch::FromOQL("SELECT $sFieldClass WHERE 1=0"));
}
}
// Prevent datetimepicker popup to be truncated
if ($oField instanceof DateTimeField) {
$oField->SetDateTimePickerWidgetParent($sDateTimePickerWidgetParent);
@@ -1560,7 +1621,7 @@ class ObjectController extends BrickController
// We have to check whether the 'operation' parameter is defined or not in order to know if the form is required via ajax (to be displayed as a modal dialog) or if it's a lifecycle call from a existing form.
if (empty($sOperation))
{
$oResponse = $this->render('itop-portal-base/portal/templates/bricks/object/modal.html.twig', $aData);
$oResponse = $this->render($this->GetTemplatePath('modal'), $aData);
}
else
{
@@ -1580,7 +1641,7 @@ class ObjectController extends BrickController
}
}
$aData['sPageTitle'] = $aData['form']['title'];
$oResponse = $this->render('itop-portal-base/portal/templates/bricks/object/layout.html.twig', $aData);
$oResponse = $this->render($this->GetTemplatePath('page'), $aData);
}
return $oResponse;
@@ -1614,7 +1675,7 @@ class ObjectController extends BrickController
if (!empty($sBrickId))
{
$oBrick = $this->oBrickCollection->GetBrickById($sBrickId);
$sTemplatePath = $oBrick->GetPageTemplatePath();
$sTemplatePath = $oBrick->GetTemplatePath('page');
$aData['sBrickId'] = $sBrickId;
$aData['oBrick'] = $oBrick;

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