Compare commits

..

479 Commits

Author SHA1 Message Date
Anne-Cath
8fc5dadad9 WIP 2025-09-08 16:13:17 +02:00
Anne-Cath
036a5d623b WIP 2025-09-08 16:10:52 +02:00
Anne-Cath
e8e8828f66 WIP 2025-09-08 16:03:52 +02:00
Anne-Cath
bbdef6b730 WIP 2025-09-08 15:56:15 +02:00
Anne-Cath
dd2f6e7413 WIP 2025-09-08 15:21:34 +02:00
Anne-Cath
ab4993debe WIP 2025-09-08 15:10:56 +02:00
Anne-Cath
455ce42a2f composer 2025-09-04 11:30:54 +02:00
Anne-Cath
f4ebbfe8ea move file 2025-09-04 11:25:44 +02:00
Anne-Cath
8d9069728a Rename file 2025-09-04 11:22:41 +02:00
Anne-Cath
80c699c56a move file 2025-09-04 11:22:30 +02:00
Anne-Cath
e923c0fef3 move file 2025-09-04 11:21:24 +02:00
Anne-Cath
70fd8ed128 Rename file 2025-09-04 11:20:14 +02:00
anne-catherine
196ceba1bb Merge branch 'split-file_counter.class.inc.php' into feature/2535-split_file 2025-09-04 09:12:58 +00:00
Potherca-Bot
7d82057e66 Merge branch 'split-file_counter.class.inc.php_KeyValueStore.php' into split-file_counter.class.inc.php 2025-09-04 09:10:58 +00:00
Potherca-Bot
fc9abc95cb Merge branch 'split-file_counter.class.inc.php_ItopCounter.php' into split-file_counter.class.inc.php 2025-09-04 09:10:57 +00:00
Potherca-Bot
ddff020a1d Changes content in separated file 'KeyValueStore.php'. 2025-09-04 09:10:57 +00:00
Potherca-Bot
b803db38b9 Changes content in separated file 'ItopCounter.php'. 2025-09-04 09:10:57 +00:00
Potherca-Bot
010edf1407 Adds separate file for 'KeyValueStore.php'. 2025-09-04 09:10:57 +00:00
Potherca-Bot
0006491304 Adds separate file for 'ItopCounter.php'. 2025-09-04 09:10:57 +00:00
anne-catherine
e0674fb797 end merge 2025-09-04 07:53:12 +00:00
Anne-Cath
f4fbbf3a4f Rename folder 2025-09-04 09:44:43 +02:00
Anne-Cath
392957d849 Move folder 2025-09-04 09:40:39 +02:00
Anne-Cath
71604e65d2 Rename folder 2025-09-04 09:38:12 +02:00
Anne-Cath
648692409b Move folder 2025-09-04 09:35:39 +02:00
Anne-Cath
950f283e9b Rename file 2025-09-04 09:29:46 +02:00
Anne-Cath
10e2679887 WIP 2025-09-04 09:28:59 +02:00
anne-catherine
8e789d51ce end merge 2025-09-03 09:18:40 +00:00
Anne-Cath
7ed43c3e50 N°6932 - Split files 2025-09-03 11:16:06 +02:00
Potherca-Bot
90fc39c409 Merge branch 'split-file_relationgraph.class.inc.php_RelationRedundancyNode.php' into split-file_relationgraph.class.inc.php 2025-09-03 09:12:57 +00:00
Potherca-Bot
88a0678149 Merge branch 'split-file_relationgraph.class.inc.php_RelationObjectNode.php' into split-file_relationgraph.class.inc.php 2025-09-03 09:12:57 +00:00
Potherca-Bot
1f7d9c0d0f Merge branch 'split-file_relationgraph.class.inc.php_RelationEdge.php' into split-file_relationgraph.class.inc.php 2025-09-03 09:12:57 +00:00
Potherca-Bot
e4c025a7f6 Changes content in separated file 'RelationRedundancyNode.php'. 2025-09-03 09:12:56 +00:00
Potherca-Bot
f9d1475147 Changes content in separated file 'RelationObjectNode.php'. 2025-09-03 09:12:56 +00:00
Potherca-Bot
be173eaf1b Adds separate file for 'RelationRedundancyNode.php'. 2025-09-03 09:12:56 +00:00
Potherca-Bot
b7e69c65a8 Adds separate file for 'RelationObjectNode.php'. 2025-09-03 09:12:56 +00:00
Potherca-Bot
980cecccad Changes content in separated file 'RelationEdge.php'. 2025-09-03 09:12:55 +00:00
Potherca-Bot
e2115e61df Adds separate file for 'RelationEdge.php'. 2025-09-03 09:12:55 +00:00
anne-catherine
e013c28d67 Merge branch 'split-file_bulkexport.class.inc.php' into feature/2535-split_file 2025-09-03 09:02:36 +00:00
Potherca-Bot
f7d37b7ee1 Merge branch 'split-file_bulkexport.class.inc.php_BulkExportResult.php' into split-file_bulkexport.class.inc.php 2025-09-03 09:01:49 +00:00
Potherca-Bot
a2b1b77798 Merge branch 'split-file_bulkexport.class.inc.php_BulkExportResultGC.php' into split-file_bulkexport.class.inc.php 2025-09-03 09:01:49 +00:00
Potherca-Bot
aa048b65f3 Merge branch 'split-file_bulkexport.class.inc.php_BulkExport.php' into split-file_bulkexport.class.inc.php 2025-09-03 09:01:49 +00:00
Potherca-Bot
c1e915188a Changes content in separated file 'BulkExportResult.php'. 2025-09-03 09:01:48 +00:00
Potherca-Bot
4b374c7e9e Merge branch 'split-file_bulkexport.class.inc.php_BulkExportMissingParameterException.php' into split-file_bulkexport.class.inc.php 2025-09-03 09:01:48 +00:00
Potherca-Bot
554fec71f0 Merge branch 'split-file_bulkexport.class.inc.php_BulkExportException.php' into split-file_bulkexport.class.inc.php 2025-09-03 09:01:48 +00:00
Potherca-Bot
c4385c1627 Changes content in separated file 'BulkExportResultGC.php'. 2025-09-03 09:01:47 +00:00
Potherca-Bot
2cf62dc72e Changes content in separated file 'BulkExport.php'. 2025-09-03 09:01:47 +00:00
Potherca-Bot
ecf4658d2c Adds separate file for 'BulkExportResult.php'. 2025-09-03 09:01:47 +00:00
Potherca-Bot
26826197ce Adds separate file for 'BulkExportResultGC.php'. 2025-09-03 09:01:47 +00:00
Potherca-Bot
f52bfddc58 Adds separate file for 'BulkExport.php'. 2025-09-03 09:01:47 +00:00
Potherca-Bot
540ff50ce1 Changes content in separated file 'BulkExportMissingParameterException.php'. 2025-09-03 09:01:46 +00:00
Potherca-Bot
fa41afccc8 Changes content in separated file 'BulkExportException.php'. 2025-09-03 09:01:46 +00:00
Potherca-Bot
31db7201c6 Adds separate file for 'BulkExportMissingParameterException.php'. 2025-09-03 09:01:46 +00:00
Potherca-Bot
4375e4085c Adds separate file for 'BulkExportException.php'. 2025-09-03 09:01:45 +00:00
anne-catherine
fbfbc78e2d Merge branch 'split-file_cmdbchangeop.class.inc.php' into feature/2535-split_file 2025-09-02 22:31:02 +00:00
Potherca-Bot
6746136db3 Merge branch 'split-file_cmdbchangeop.class.inc.php_iCMDBChangeOp.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:27 +00:00
Potherca-Bot
ccb60a2d41 Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpSetAttributeURL.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:27 +00:00
Potherca-Bot
b799a38ec4 Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpSetAttributeText.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:27 +00:00
Potherca-Bot
ff3da21f36 Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpSetAttributeTagSet.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:27 +00:00
Potherca-Bot
2ee4595952 Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpSetAttributeScalar.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:26 +00:00
Potherca-Bot
40a1ca98e1 Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpSetAttribute.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:26 +00:00
Potherca-Bot
ab28f59a19 Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpSetAttributeOneWayPassword.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:26 +00:00
Potherca-Bot
4a6804d084 Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpSetAttributeLongText.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:26 +00:00
Potherca-Bot
1e4cf8931b Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpSetAttributeLinksTune.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:26 +00:00
Potherca-Bot
3c2a4c880b Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpSetAttributeLinks.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:26 +00:00
Potherca-Bot
28ddfe763c Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpSetAttributeLinksAddRemove.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:25 +00:00
Potherca-Bot
ad814df467 Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpSetAttributeHTML.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:25 +00:00
Potherca-Bot
bcc42a09e3 Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpSetAttributeEncrypted.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:25 +00:00
Potherca-Bot
e655e80157 Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpSetAttributeCustomFields.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:25 +00:00
Potherca-Bot
1098e68bd0 Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpSetAttributeCaseLog.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:25 +00:00
Potherca-Bot
b48e3e8bc5 Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpSetAttributeBlob.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:25 +00:00
Potherca-Bot
346b105054 Changes content in separated file 'iCMDBChangeOp.php'. 2025-09-02 22:28:24 +00:00
Potherca-Bot
14095baf67 Changes content in separated file 'CMDBChangeOpSetAttributeURL.php'. 2025-09-02 22:28:24 +00:00
Potherca-Bot
199e02aa43 Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpPlugin.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:24 +00:00
Potherca-Bot
30ff03bce0 Adds separate file for 'iCMDBChangeOp.php'. 2025-09-02 22:28:24 +00:00
Potherca-Bot
a4d1218707 Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOp.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:24 +00:00
Potherca-Bot
b0bf38f0a4 Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpDelete.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:24 +00:00
Potherca-Bot
ec72dc9cff Merge branch 'split-file_cmdbchangeop.class.inc.php_CMDBChangeOpCreate.php' into split-file_cmdbchangeop.class.inc.php 2025-09-02 22:28:24 +00:00
Potherca-Bot
ea9c458c9f Changes content in separated file 'CMDBChangeOpSetAttributeText.php'. 2025-09-02 22:28:23 +00:00
Potherca-Bot
500ae157b3 Changes content in separated file 'CMDBChangeOpSetAttributeTagSet.php'. 2025-09-02 22:28:23 +00:00
Potherca-Bot
5de3a5331b Changes content in separated file 'CMDBChangeOpSetAttributeScalar.php'. 2025-09-02 22:28:23 +00:00
Potherca-Bot
fddf54b863 Adds separate file for 'CMDBChangeOpSetAttributeURL.php'. 2025-09-02 22:28:23 +00:00
Potherca-Bot
9fba36ae29 Adds separate file for 'CMDBChangeOpSetAttributeText.php'. 2025-09-02 22:28:23 +00:00
Potherca-Bot
d2ca1d59a6 Adds separate file for 'CMDBChangeOpSetAttributeTagSet.php'. 2025-09-02 22:28:23 +00:00
Potherca-Bot
714079df9f Changes content in separated file 'CMDBChangeOpSetAttribute.php'. 2025-09-02 22:28:22 +00:00
Potherca-Bot
b18733ac31 Changes content in separated file 'CMDBChangeOpSetAttributeOneWayPassword.php'. 2025-09-02 22:28:22 +00:00
Potherca-Bot
32ce6ac336 Changes content in separated file 'CMDBChangeOpSetAttributeLongText.php'. 2025-09-02 22:28:22 +00:00
Potherca-Bot
36de69b3d0 Adds separate file for 'CMDBChangeOpSetAttributeScalar.php'. 2025-09-02 22:28:22 +00:00
Potherca-Bot
17b05efbba Adds separate file for 'CMDBChangeOpSetAttribute.php'. 2025-09-02 22:28:22 +00:00
Potherca-Bot
079cceb48b Adds separate file for 'CMDBChangeOpSetAttributeOneWayPassword.php'. 2025-09-02 22:28:22 +00:00
Potherca-Bot
0c5e032d9a Adds separate file for 'CMDBChangeOpSetAttributeLongText.php'. 2025-09-02 22:28:22 +00:00
Potherca-Bot
407b41155c Changes content in separated file 'CMDBChangeOpSetAttributeLinksTune.php'. 2025-09-02 22:28:21 +00:00
Potherca-Bot
c2479757f4 Changes content in separated file 'CMDBChangeOpSetAttributeLinks.php'. 2025-09-02 22:28:21 +00:00
Potherca-Bot
2d27794f85 Changes content in separated file 'CMDBChangeOpSetAttributeLinksAddRemove.php'. 2025-09-02 22:28:21 +00:00
Potherca-Bot
47f0302967 Adds separate file for 'CMDBChangeOpSetAttributeLinksTune.php'. 2025-09-02 22:28:21 +00:00
Potherca-Bot
d9f49a7958 Adds separate file for 'CMDBChangeOpSetAttributeLinks.php'. 2025-09-02 22:28:21 +00:00
Potherca-Bot
8da798be3b Adds separate file for 'CMDBChangeOpSetAttributeLinksAddRemove.php'. 2025-09-02 22:28:21 +00:00
Potherca-Bot
e49b3c7366 Changes content in separated file 'CMDBChangeOpSetAttributeHTML.php'. 2025-09-02 22:28:20 +00:00
Potherca-Bot
d54abbe401 Changes content in separated file 'CMDBChangeOpSetAttributeEncrypted.php'. 2025-09-02 22:28:20 +00:00
Potherca-Bot
23a84b7864 Changes content in separated file 'CMDBChangeOpSetAttributeCustomFields.php'. 2025-09-02 22:28:20 +00:00
Potherca-Bot
5836b2a403 Changes content in separated file 'CMDBChangeOpSetAttributeCaseLog.php'. 2025-09-02 22:28:20 +00:00
Potherca-Bot
50feffe40f Adds separate file for 'CMDBChangeOpSetAttributeHTML.php'. 2025-09-02 22:28:20 +00:00
Potherca-Bot
c9682227b8 Adds separate file for 'CMDBChangeOpSetAttributeEncrypted.php'. 2025-09-02 22:28:20 +00:00
Potherca-Bot
b7f0915e2f Adds separate file for 'CMDBChangeOpSetAttributeCustomFields.php'. 2025-09-02 22:28:20 +00:00
Potherca-Bot
de93208fde Changes content in separated file 'CMDBChangeOpSetAttributeBlob.php'. 2025-09-02 22:28:19 +00:00
Potherca-Bot
e07e435f65 Changes content in separated file 'CMDBChangeOpPlugin.php'. 2025-09-02 22:28:19 +00:00
Potherca-Bot
d8876eef24 Changes content in separated file 'CMDBChangeOp.php'. 2025-09-02 22:28:19 +00:00
Potherca-Bot
e05b519215 Adds separate file for 'CMDBChangeOpSetAttributeCaseLog.php'. 2025-09-02 22:28:19 +00:00
Potherca-Bot
67e288fbc8 Adds separate file for 'CMDBChangeOpSetAttributeBlob.php'. 2025-09-02 22:28:19 +00:00
Potherca-Bot
621b71f672 Adds separate file for 'CMDBChangeOpPlugin.php'. 2025-09-02 22:28:19 +00:00
Potherca-Bot
4adefa5cd8 Adds separate file for 'CMDBChangeOp.php'. 2025-09-02 22:28:19 +00:00
Potherca-Bot
4993240c19 Changes content in separated file 'CMDBChangeOpDelete.php'. 2025-09-02 22:28:18 +00:00
Potherca-Bot
c21169d6a7 Changes content in separated file 'CMDBChangeOpCreate.php'. 2025-09-02 22:28:18 +00:00
Potherca-Bot
af78129b7d Adds separate file for 'CMDBChangeOpDelete.php'. 2025-09-02 22:28:18 +00:00
Potherca-Bot
3175734b4f Adds separate file for 'CMDBChangeOpCreate.php'. 2025-09-02 22:28:18 +00:00
anne-catherine
a27a4d9f64 Merge branch 'split-file_simplecrypt.class.inc.php' into feature/2535-split_file 2025-09-02 21:02:57 +00:00
Potherca-Bot
132876fc57 Merge branch 'split-file_simplecrypt.class.inc.php_SimpleCryptSodiumEngine.php' into split-file_simplecrypt.class.inc.php 2025-09-02 18:15:35 +00:00
Potherca-Bot
a454e9cb84 Merge branch 'split-file_simplecrypt.class.inc.php_SimpleCryptSimpleEngine.php' into split-file_simplecrypt.class.inc.php 2025-09-02 18:15:35 +00:00
Potherca-Bot
7e6389eac2 Merge branch 'split-file_simplecrypt.class.inc.php_SimpleCrypt.php' into split-file_simplecrypt.class.inc.php 2025-09-02 18:15:34 +00:00
Potherca-Bot
4b86b1680b Merge branch 'split-file_simplecrypt.class.inc.php_SimpleCryptOpenSSLMcryptCompatibilityEngine.php' into split-file_simplecrypt.class.inc.php 2025-09-02 18:15:34 +00:00
Potherca-Bot
1d6d58384c Merge branch 'split-file_simplecrypt.class.inc.php_SimpleCryptOpenSSLEngine.php' into split-file_simplecrypt.class.inc.php 2025-09-02 18:15:34 +00:00
Potherca-Bot
f1f2a74394 Merge branch 'split-file_simplecrypt.class.inc.php_SimpleCryptMcryptEngine.php' into split-file_simplecrypt.class.inc.php 2025-09-02 18:15:34 +00:00
Potherca-Bot
bf575889cc Merge branch 'split-file_simplecrypt.class.inc.php_CryptEngine.php' into split-file_simplecrypt.class.inc.php 2025-09-02 18:15:34 +00:00
Potherca-Bot
43a9fee52b Changes content in separated file 'SimpleCryptSodiumEngine.php'. 2025-09-02 18:15:33 +00:00
Potherca-Bot
fd1a457ac3 Changes content in separated file 'SimpleCryptSimpleEngine.php'. 2025-09-02 18:15:33 +00:00
Potherca-Bot
afd8c487c4 Changes content in separated file 'SimpleCrypt.php'. 2025-09-02 18:15:33 +00:00
Potherca-Bot
41b92e2d3d Changes content in separated file 'SimpleCryptOpenSSLMcryptCompatibilityEngine.php'. 2025-09-02 18:15:33 +00:00
Potherca-Bot
b12d185376 Adds separate file for 'SimpleCryptSodiumEngine.php'. 2025-09-02 18:15:33 +00:00
Potherca-Bot
eaac1c293e Adds separate file for 'SimpleCryptSimpleEngine.php'. 2025-09-02 18:15:33 +00:00
Potherca-Bot
f7a97bd590 Adds separate file for 'SimpleCrypt.php'. 2025-09-02 18:15:33 +00:00
Potherca-Bot
29136c269a Changes content in separated file 'SimpleCryptOpenSSLEngine.php'. 2025-09-02 18:15:32 +00:00
Potherca-Bot
1db8aa811e Changes content in separated file 'SimpleCryptMcryptEngine.php'. 2025-09-02 18:15:32 +00:00
Potherca-Bot
d44d538faf Changes content in separated file 'CryptEngine.php'. 2025-09-02 18:15:32 +00:00
Potherca-Bot
8f5cb404c4 Adds separate file for 'SimpleCryptOpenSSLMcryptCompatibilityEngine.php'. 2025-09-02 18:15:32 +00:00
Potherca-Bot
caef7a244e Adds separate file for 'SimpleCryptOpenSSLEngine.php'. 2025-09-02 18:15:32 +00:00
Potherca-Bot
bd514f7a9a Adds separate file for 'SimpleCryptMcryptEngine.php'. 2025-09-02 18:15:32 +00:00
Potherca-Bot
212b98724b Adds separate file for 'CryptEngine.php'. 2025-09-02 18:15:31 +00:00
anne-catherine
afcbc8ce40 Merge branch 'split-file_trigger.class.inc.php' into feature/2535-split_file 2025-09-02 18:02:45 +00:00
Potherca-Bot
df68d2a8da Merge branch 'split-file_trigger.class.inc.php_Trigger.php' into split-file_trigger.class.inc.php 2025-09-02 18:00:48 +00:00
Potherca-Bot
6870d4f4db Merge branch 'split-file_trigger.class.inc.php_TriggerOnThresholdReached.php' into split-file_trigger.class.inc.php 2025-09-02 18:00:48 +00:00
Potherca-Bot
7553ee2510 Merge branch 'split-file_trigger.class.inc.php_TriggerOnStateLeave.php' into split-file_trigger.class.inc.php 2025-09-02 18:00:48 +00:00
Potherca-Bot
1a999b1a1c Merge branch 'split-file_trigger.class.inc.php_TriggerOnStateEnter.php' into split-file_trigger.class.inc.php 2025-09-02 18:00:48 +00:00
Potherca-Bot
182ae5d3aa Merge branch 'split-file_trigger.class.inc.php_TriggerOnStateChange.php' into split-file_trigger.class.inc.php 2025-09-02 18:00:48 +00:00
Potherca-Bot
4edaacc2f5 Merge branch 'split-file_trigger.class.inc.php_TriggerOnPortalUpdate.php' into split-file_trigger.class.inc.php 2025-09-02 18:00:48 +00:00
Potherca-Bot
c98a11623e Merge branch 'split-file_trigger.class.inc.php_TriggerOnObjectUpdate.php' into split-file_trigger.class.inc.php 2025-09-02 18:00:47 +00:00
Potherca-Bot
9feb15f5f6 Merge branch 'split-file_trigger.class.inc.php_TriggerOnObject.php' into split-file_trigger.class.inc.php 2025-09-02 18:00:47 +00:00
Potherca-Bot
a7941c932b Merge branch 'split-file_trigger.class.inc.php_TriggerOnObjectMention.php' into split-file_trigger.class.inc.php 2025-09-02 18:00:47 +00:00
Potherca-Bot
4cfc2a1b26 Merge branch 'split-file_trigger.class.inc.php_TriggerOnObjectDelete.php' into split-file_trigger.class.inc.php 2025-09-02 18:00:47 +00:00
Potherca-Bot
7db88f256f Merge branch 'split-file_trigger.class.inc.php_TriggerOnObjectCreate.php' into split-file_trigger.class.inc.php 2025-09-02 18:00:47 +00:00
Potherca-Bot
0066b24e8f Merge branch 'split-file_trigger.class.inc.php_TriggerOnAttributeBlobDownload.php' into split-file_trigger.class.inc.php 2025-09-02 18:00:47 +00:00
Potherca-Bot
1b96f5b071 Changes content in separated file 'Trigger.php'. 2025-09-02 18:00:46 +00:00
Potherca-Bot
4b2ae38173 Changes content in separated file 'TriggerOnThresholdReached.php'. 2025-09-02 18:00:46 +00:00
Potherca-Bot
a13e2b0b00 Changes content in separated file 'TriggerOnStateLeave.php'. 2025-09-02 18:00:46 +00:00
Potherca-Bot
8f09b8149b Merge branch 'split-file_trigger.class.inc.php_lnkTriggerAction.php' into split-file_trigger.class.inc.php 2025-09-02 18:00:46 +00:00
Potherca-Bot
ff69719b8e Adds separate file for 'Trigger.php'. 2025-09-02 18:00:46 +00:00
Potherca-Bot
9c35d9edc2 Adds separate file for 'TriggerOnThresholdReached.php'. 2025-09-02 18:00:46 +00:00
Potherca-Bot
f9f75f9117 Changes content in separated file 'TriggerOnStateEnter.php'. 2025-09-02 18:00:45 +00:00
Potherca-Bot
48e3d7f67f Changes content in separated file 'TriggerOnStateChange.php'. 2025-09-02 18:00:45 +00:00
Potherca-Bot
0246951cf8 Changes content in separated file 'TriggerOnPortalUpdate.php'. 2025-09-02 18:00:45 +00:00
Potherca-Bot
fbd76e6969 Adds separate file for 'TriggerOnStateLeave.php'. 2025-09-02 18:00:45 +00:00
Potherca-Bot
559fe0be01 Adds separate file for 'TriggerOnStateEnter.php'. 2025-09-02 18:00:45 +00:00
Potherca-Bot
e6a8238924 Adds separate file for 'TriggerOnStateChange.php'. 2025-09-02 18:00:45 +00:00
Potherca-Bot
496f548aea Adds separate file for 'TriggerOnPortalUpdate.php'. 2025-09-02 18:00:45 +00:00
Potherca-Bot
4a2e37fa84 Changes content in separated file 'TriggerOnObjectUpdate.php'. 2025-09-02 18:00:44 +00:00
Potherca-Bot
315f275a6d Changes content in separated file 'TriggerOnObject.php'. 2025-09-02 18:00:44 +00:00
Potherca-Bot
d6118d5a96 Changes content in separated file 'TriggerOnObjectMention.php'. 2025-09-02 18:00:44 +00:00
Potherca-Bot
572793b7b8 Adds separate file for 'TriggerOnObjectUpdate.php'. 2025-09-02 18:00:44 +00:00
Potherca-Bot
391ec877c8 Adds separate file for 'TriggerOnObject.php'. 2025-09-02 18:00:44 +00:00
Potherca-Bot
4151aa5ac1 Adds separate file for 'TriggerOnObjectMention.php'. 2025-09-02 18:00:44 +00:00
Potherca-Bot
c36939cf85 Changes content in separated file 'TriggerOnObjectDelete.php'. 2025-09-02 18:00:43 +00:00
Potherca-Bot
3b0897fd9c Changes content in separated file 'TriggerOnObjectCreate.php'. 2025-09-02 18:00:43 +00:00
Potherca-Bot
a11c87c6c2 Changes content in separated file 'TriggerOnAttributeBlobDownload.php'. 2025-09-02 18:00:43 +00:00
Potherca-Bot
0a2492228b Adds separate file for 'TriggerOnObjectDelete.php'. 2025-09-02 18:00:43 +00:00
Potherca-Bot
36a1dbd34d Adds separate file for 'TriggerOnObjectCreate.php'. 2025-09-02 18:00:43 +00:00
Potherca-Bot
fc988d1eb0 Adds separate file for 'TriggerOnAttributeBlobDownload.php'. 2025-09-02 18:00:43 +00:00
Potherca-Bot
8d0f685fad Changes content in separated file 'lnkTriggerAction.php'. 2025-09-02 18:00:42 +00:00
Potherca-Bot
9974d59f15 Adds separate file for 'lnkTriggerAction.php'. 2025-09-02 18:00:42 +00:00
Anne-Cath
47aee14362 Move to sources Core BulkChange 2025-09-02 18:49:32 +02:00
anne-catherine
a31e3450bf Merge branch 'split-file_bulkchange.class.inc.php' into feature/2535-split_file 2025-09-02 16:46:15 +00:00
Potherca-Bot
c931e3f18a Merge branch 'split-file_bulkchange.class.inc.php_RowStatus.php' into split-file_bulkchange.class.inc.php 2025-09-02 16:42:23 +00:00
Potherca-Bot
185e03d8e8 Merge branch 'split-file_bulkchange.class.inc.php_RowStatus_NoChange.php' into split-file_bulkchange.class.inc.php 2025-09-02 16:42:23 +00:00
Potherca-Bot
e8f0542f11 Merge branch 'split-file_bulkchange.class.inc.php_RowStatus_NewObj.php' into split-file_bulkchange.class.inc.php 2025-09-02 16:42:22 +00:00
Potherca-Bot
69fa0f71d0 Merge branch 'split-file_bulkchange.class.inc.php_RowStatus_Modify.php' into split-file_bulkchange.class.inc.php 2025-09-02 16:42:22 +00:00
Potherca-Bot
03e8e77596 Merge branch 'split-file_bulkchange.class.inc.php_RowStatus_Issue.php' into split-file_bulkchange.class.inc.php 2025-09-02 16:42:22 +00:00
Potherca-Bot
c67bf66bd9 Merge branch 'split-file_bulkchange.class.inc.php_RowStatus_Error.php' into split-file_bulkchange.class.inc.php 2025-09-02 16:42:21 +00:00
Potherca-Bot
3c23b04608 Merge branch 'split-file_bulkchange.class.inc.php_RowStatus_Disappeared.php' into split-file_bulkchange.class.inc.php 2025-09-02 16:42:21 +00:00
Potherca-Bot
0891272aa3 Merge branch 'split-file_bulkchange.class.inc.php_ReportValue.php' into split-file_bulkchange.class.inc.php 2025-09-02 16:42:21 +00:00
Potherca-Bot
c6c3f7b421 Merge branch 'split-file_bulkchange.class.inc.php_CellStatus_Void.php' into split-file_bulkchange.class.inc.php 2025-09-02 16:42:21 +00:00
Potherca-Bot
5f3aa0d083 Merge branch 'split-file_bulkchange.class.inc.php_CellStatus_SearchIssue.php' into split-file_bulkchange.class.inc.php 2025-09-02 16:42:20 +00:00
Potherca-Bot
046ce13073 Merge branch 'split-file_bulkchange.class.inc.php_CellStatus_NullIssue.php' into split-file_bulkchange.class.inc.php 2025-09-02 16:42:20 +00:00
Potherca-Bot
a64ab695ce Merge branch 'split-file_bulkchange.class.inc.php_CellStatus_Modify.php' into split-file_bulkchange.class.inc.php 2025-09-02 16:42:20 +00:00
Potherca-Bot
020e58b112 Merge branch 'split-file_bulkchange.class.inc.php_CellStatus_Issue.php' into split-file_bulkchange.class.inc.php 2025-09-02 16:42:20 +00:00
Potherca-Bot
c372707124 Merge branch 'split-file_bulkchange.class.inc.php_CellStatus_Ambiguous.php' into split-file_bulkchange.class.inc.php 2025-09-02 16:42:20 +00:00
Potherca-Bot
6a462d25e0 Changes content in separated file 'RowStatus.php'. 2025-09-02 16:42:19 +00:00
Potherca-Bot
288ffd1830 Merge branch 'split-file_bulkchange.class.inc.php_CellChangeSpec.php' into split-file_bulkchange.class.inc.php 2025-09-02 16:42:19 +00:00
Potherca-Bot
02c3ca4724 Merge branch 'split-file_bulkchange.class.inc.php_BulkChange.php' into split-file_bulkchange.class.inc.php 2025-09-02 16:42:19 +00:00
Potherca-Bot
5b5ab86862 Changes content in separated file 'RowStatus_NoChange.php'. 2025-09-02 16:42:18 +00:00
Potherca-Bot
62122b0ee6 Changes content in separated file 'RowStatus_NewObj.php'. 2025-09-02 16:42:18 +00:00
Potherca-Bot
7aaa4a2b0d Adds separate file for 'RowStatus.php'. 2025-09-02 16:42:18 +00:00
Potherca-Bot
786651b35c Adds separate file for 'RowStatus_NoChange.php'. 2025-09-02 16:42:18 +00:00
Potherca-Bot
30b793eed8 Changes content in separated file 'RowStatus_Modify.php'. 2025-09-02 16:42:17 +00:00
Potherca-Bot
3f3d9b3d2e Changes content in separated file 'RowStatus_Issue.php'. 2025-09-02 16:42:17 +00:00
Potherca-Bot
dc3c6ea6ce Adds separate file for 'RowStatus_NewObj.php'. 2025-09-02 16:42:17 +00:00
Potherca-Bot
a73321dd02 Adds separate file for 'RowStatus_Modify.php'. 2025-09-02 16:42:17 +00:00
Potherca-Bot
3edcdc452e Changes content in separated file 'RowStatus_Error.php'. 2025-09-02 16:42:16 +00:00
Potherca-Bot
0c93971e13 Changes content in separated file 'RowStatus_Disappeared.php'. 2025-09-02 16:42:16 +00:00
Potherca-Bot
5a59b1870d Adds separate file for 'RowStatus_Issue.php'. 2025-09-02 16:42:16 +00:00
Potherca-Bot
19bb7e5043 Adds separate file for 'RowStatus_Error.php'. 2025-09-02 16:42:16 +00:00
Potherca-Bot
8e08be2258 Adds separate file for 'RowStatus_Disappeared.php'. 2025-09-02 16:42:16 +00:00
Potherca-Bot
22834d32a3 Changes content in separated file 'ReportValue.php'. 2025-09-02 16:42:15 +00:00
Potherca-Bot
23407cd095 Changes content in separated file 'CellStatus_Void.php'. 2025-09-02 16:42:15 +00:00
Potherca-Bot
8403273c0b Adds separate file for 'ReportValue.php'. 2025-09-02 16:42:15 +00:00
Potherca-Bot
d5dc3c0d74 Adds separate file for 'CellStatus_Void.php'. 2025-09-02 16:42:15 +00:00
Potherca-Bot
fbbdcfa7b9 Changes content in separated file 'CellStatus_SearchIssue.php'. 2025-09-02 16:42:14 +00:00
Potherca-Bot
7a528e276f Changes content in separated file 'CellStatus_NullIssue.php'. 2025-09-02 16:42:14 +00:00
Potherca-Bot
ed55bfa6aa Adds separate file for 'CellStatus_SearchIssue.php'. 2025-09-02 16:42:14 +00:00
Potherca-Bot
7f62a78529 Adds separate file for 'CellStatus_NullIssue.php'. 2025-09-02 16:42:14 +00:00
Potherca-Bot
cf51bddbc9 Changes content in separated file 'CellStatus_Modify.php'. 2025-09-02 16:42:13 +00:00
Potherca-Bot
adf3902c37 Changes content in separated file 'CellStatus_Issue.php'. 2025-09-02 16:42:13 +00:00
Potherca-Bot
6f5bed6b98 Changes content in separated file 'CellStatus_Ambiguous.php'. 2025-09-02 16:42:13 +00:00
Potherca-Bot
7079cab1de Adds separate file for 'CellStatus_Modify.php'. 2025-09-02 16:42:13 +00:00
Potherca-Bot
19188ac2fc Adds separate file for 'CellStatus_Issue.php'. 2025-09-02 16:42:13 +00:00
Potherca-Bot
d543e311dd Changes content in separated file 'CellChangeSpec.php'. 2025-09-02 16:42:12 +00:00
Potherca-Bot
19ea531961 Changes content in separated file 'BulkChange.php'. 2025-09-02 16:42:12 +00:00
Potherca-Bot
9bee4bdb5c Adds separate file for 'CellStatus_Ambiguous.php'. 2025-09-02 16:42:12 +00:00
Potherca-Bot
2b4e2939fe Adds separate file for 'CellChangeSpec.php'. 2025-09-02 16:42:12 +00:00
Potherca-Bot
2c8eac0e3b Adds separate file for 'BulkChange.php'. 2025-09-02 16:42:12 +00:00
Anne-Cath
2dd38e81c5 rollback file autoload.php 2025-08-28 14:49:54 +02:00
Anne-Cath
c052c40f9d update autoloader 2025-08-28 11:17:43 +02:00
anne-catherine
89fff9075d end merge 2025-08-28 09:08:22 +00:00
anne-catherine
97b4c80e0b update attributedef.class.inc.php 2025-08-28 09:07:44 +00:00
Potherca-Bot
905388825c Merge branch 'split-file_attributedef.class.inc.php_MissingColumnException.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:42 +00:00
Potherca-Bot
d02dec7a09 Merge branch 'split-file_attributedef.class.inc.php_iAttributeNoGroupBy.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:41 +00:00
Potherca-Bot
438ecfebdf Merge branch 'split-file_attributedef.class.inc.php_AttributeURL.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:41 +00:00
Potherca-Bot
8aa7e52fa2 Merge branch 'split-file_attributedef.class.inc.php_AttributeText.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:41 +00:00
Potherca-Bot
27642d5872 Merge branch 'split-file_attributedef.class.inc.php_AttributeTemplateText.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:41 +00:00
Potherca-Bot
4754009d4f Merge branch 'split-file_attributedef.class.inc.php_AttributeTemplateString.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:40 +00:00
Potherca-Bot
967911c538 Merge branch 'split-file_attributedef.class.inc.php_AttributeTemplateHTML.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:40 +00:00
Potherca-Bot
b3f069fec0 Merge branch 'split-file_attributedef.class.inc.php_AttributeTagSet.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:40 +00:00
Potherca-Bot
59db7535c3 Merge branch 'split-file_attributedef.class.inc.php_AttributeTable.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:39 +00:00
Potherca-Bot
f1657ac695 Merge branch 'split-file_attributedef.class.inc.php_AttributeSubItem.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:39 +00:00
Potherca-Bot
d307f4861f Merge branch 'split-file_attributedef.class.inc.php_AttributeString.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:39 +00:00
Potherca-Bot
6341e7e263 Merge branch 'split-file_attributedef.class.inc.php_AttributeStopWatch.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:38 +00:00
Potherca-Bot
0efec39071 Merge branch 'split-file_attributedef.class.inc.php_AttributeSet.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:38 +00:00
Potherca-Bot
e1ebeac986 Merge branch 'split-file_attributedef.class.inc.php_AttributeRedundancySettings.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:38 +00:00
Potherca-Bot
68c5d7d33b Merge branch 'split-file_attributedef.class.inc.php_AttributeQueryAttCodeSet.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:37 +00:00
Potherca-Bot
2cefaba0d8 Merge branch 'split-file_attributedef.class.inc.php_AttributePropertySet.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:37 +00:00
Potherca-Bot
a57de6f090 Merge branch 'split-file_attributedef.class.inc.php_AttributePhoneNumber.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:37 +00:00
Potherca-Bot
6e63254a6b Merge branch 'split-file_attributedef.class.inc.php_AttributePercentage.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:36 +00:00
Potherca-Bot
2ae2407c24 Merge branch 'split-file_attributedef.class.inc.php_AttributePassword.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:36 +00:00
Potherca-Bot
d970f0e1e4 Merge branch 'split-file_attributedef.class.inc.php_AttributeOQL.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:36 +00:00
Potherca-Bot
b3ce941e5a Merge branch 'split-file_attributedef.class.inc.php_AttributeOneWayPassword.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:36 +00:00
Potherca-Bot
8976ad3635 Merge branch 'split-file_attributedef.class.inc.php_AttributeObsolescenceFlag.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:35 +00:00
Potherca-Bot
03d12d2485 Merge branch 'split-file_attributedef.class.inc.php_AttributeObsolescenceDate.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:35 +00:00
Potherca-Bot
582da19aaa Merge branch 'split-file_attributedef.class.inc.php_AttributeObjectKey.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:35 +00:00
Potherca-Bot
62aa33f0f3 Merge branch 'split-file_attributedef.class.inc.php_AttributeMetaEnum.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:34 +00:00
Potherca-Bot
8bb75006ba Merge branch 'split-file_attributedef.class.inc.php_AttributeLongText.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:34 +00:00
Potherca-Bot
b1881f1847 Merge branch 'split-file_attributedef.class.inc.php_AttributeLinkedSet.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:34 +00:00
Potherca-Bot
03759dffbb Merge branch 'split-file_attributedef.class.inc.php_AttributeLinkedSetIndirect.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:33 +00:00
Potherca-Bot
ada0126f9e Merge branch 'split-file_attributedef.class.inc.php_AttributeIPAddress.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:33 +00:00
Potherca-Bot
d897ddeed3 Merge branch 'split-file_attributedef.class.inc.php_AttributeInteger.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:33 +00:00
Potherca-Bot
eb14ef3c30 Merge branch 'split-file_attributedef.class.inc.php_AttributeImage.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:32 +00:00
Potherca-Bot
e12f6c92b2 Merge branch 'split-file_attributedef.class.inc.php_AttributeHTML.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:32 +00:00
Potherca-Bot
1dbc62ddf1 Merge branch 'split-file_attributedef.class.inc.php_AttributeHierarchicalKey.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:32 +00:00
Potherca-Bot
e6ac5f48b7 Merge branch 'split-file_attributedef.class.inc.php_AttributeFriendlyName.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:32 +00:00
Potherca-Bot
d32b6cc0b9 Merge branch 'split-file_attributedef.class.inc.php_AttributeFinalClass.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:31 +00:00
Potherca-Bot
63b70aa99b Merge branch 'split-file_attributedef.class.inc.php_AttributeExternalKey.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:31 +00:00
Potherca-Bot
71e006054d Merge branch 'split-file_attributedef.class.inc.php_AttributeExternalField.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:31 +00:00
Potherca-Bot
65c23c58c3 Merge branch 'split-file_attributedef.class.inc.php_AttributeEnumSet.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:30 +00:00
Potherca-Bot
8605d8667d Merge branch 'split-file_attributedef.class.inc.php_AttributeEnum.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:30 +00:00
Potherca-Bot
084b10a9a6 Merge branch 'split-file_attributedef.class.inc.php_AttributeEncryptedString.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:30 +00:00
Potherca-Bot
5ee18637bb Merge branch 'split-file_attributedef.class.inc.php_AttributeEmailAddress.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:30 +00:00
Potherca-Bot
bdbdd812e9 Merge branch 'split-file_attributedef.class.inc.php_AttributeDuration.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:29 +00:00
Potherca-Bot
2d43b8946d Merge branch 'split-file_attributedef.class.inc.php_AttributeDefinition.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:29 +00:00
Potherca-Bot
e5100ddeed Merge branch 'split-file_attributedef.class.inc.php_AttributeDecimal.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:29 +00:00
Potherca-Bot
ea9588761d Merge branch 'split-file_attributedef.class.inc.php_AttributeDeadline.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:28 +00:00
Potherca-Bot
16b34ab4e7 Merge branch 'split-file_attributedef.class.inc.php_AttributeDBFieldVoid.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:28 +00:00
Potherca-Bot
7bb8fbc793 Merge branch 'split-file_attributedef.class.inc.php_AttributeDBField.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:28 +00:00
Potherca-Bot
0816d3c84a Merge branch 'split-file_attributedef.class.inc.php_AttributeDateTime.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:28 +00:00
Potherca-Bot
66c5034ff2 Merge branch 'split-file_attributedef.class.inc.php_AttributeDate.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:27 +00:00
Potherca-Bot
03c097f5a1 Merge branch 'split-file_attributedef.class.inc.php_AttributeDashboard.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:27 +00:00
Potherca-Bot
87ca02dba3 Merge branch 'split-file_attributedef.class.inc.php_AttributeCustomFields.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:27 +00:00
Potherca-Bot
f4ba1a15fe Merge branch 'split-file_attributedef.class.inc.php_AttributeClassState.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:26 +00:00
Potherca-Bot
1977fe8cb0 Merge branch 'split-file_attributedef.class.inc.php_AttributeClass.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:26 +00:00
Potherca-Bot
91d0209253 Merge branch 'split-file_attributedef.class.inc.php_AttributeClassAttCodeSet.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:26 +00:00
Potherca-Bot
3bee8de25e Merge branch 'split-file_attributedef.class.inc.php_AttributeCaseLog.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:25 +00:00
Potherca-Bot
52db2a58ea Merge branch 'split-file_attributedef.class.inc.php_AttributeBoolean.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:25 +00:00
Potherca-Bot
16f0927d92 Merge branch 'split-file_attributedef.class.inc.php_AttributeBlob.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:25 +00:00
Potherca-Bot
bd64479687 Merge branch 'split-file_attributedef.class.inc.php_AttributeArchiveFlag.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:24 +00:00
Potherca-Bot
8436970132 Merge branch 'split-file_attributedef.class.inc.php_AttributeArchiveDate.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:24 +00:00
Potherca-Bot
08f35f451f Merge branch 'split-file_attributedef.class.inc.php_AttributeApplicationLanguage.php' into split-file_attributedef.class.inc.php 2025-08-28 09:06:24 +00:00
Potherca-Bot
dd441afa22 Changes content in separated file 'MissingColumnException.php'. 2025-08-28 09:06:23 +00:00
Potherca-Bot
5d8184a673 Changes content in separated file 'iAttributeNoGroupBy.php'. 2025-08-28 09:06:23 +00:00
Potherca-Bot
db91ed0c1d Adds separate file for 'MissingColumnException.php'. 2025-08-28 09:06:23 +00:00
Potherca-Bot
e890d62ab1 Changes content in separated file 'AttributeURL.php'. 2025-08-28 09:06:22 +00:00
Potherca-Bot
6d2b457185 Adds separate file for 'iAttributeNoGroupBy.php'. 2025-08-28 09:06:22 +00:00
Potherca-Bot
4328fc78dc Adds separate file for 'AttributeURL.php'. 2025-08-28 09:06:22 +00:00
Potherca-Bot
37914e2b7f Changes content in separated file 'AttributeText.php'. 2025-08-28 09:06:21 +00:00
Potherca-Bot
0551102364 Changes content in separated file 'AttributeTemplateText.php'. 2025-08-28 09:06:21 +00:00
Potherca-Bot
1ca369041d Adds separate file for 'AttributeText.php'. 2025-08-28 09:06:21 +00:00
Potherca-Bot
2a6a4d3460 Adds separate file for 'AttributeTemplateText.php'. 2025-08-28 09:06:21 +00:00
Potherca-Bot
9edc15f50d Changes content in separated file 'AttributeTemplateString.php'. 2025-08-28 09:06:20 +00:00
Potherca-Bot
6acb89a2fc Changes content in separated file 'AttributeTemplateHTML.php'. 2025-08-28 09:06:20 +00:00
Potherca-Bot
19803c004d Adds separate file for 'AttributeTemplateString.php'. 2025-08-28 09:06:20 +00:00
Potherca-Bot
20de262e25 Changes content in separated file 'AttributeTagSet.php'. 2025-08-28 09:06:19 +00:00
Potherca-Bot
c870fc5922 Adds separate file for 'AttributeTemplateHTML.php'. 2025-08-28 09:06:19 +00:00
Potherca-Bot
09c4a4361a Adds separate file for 'AttributeTagSet.php'. 2025-08-28 09:06:19 +00:00
Potherca-Bot
3544aa4d50 Changes content in separated file 'AttributeTable.php'. 2025-08-28 09:06:18 +00:00
Potherca-Bot
d080898b1d Changes content in separated file 'AttributeSubItem.php'. 2025-08-28 09:06:18 +00:00
Potherca-Bot
78282a80ef Adds separate file for 'AttributeTable.php'. 2025-08-28 09:06:18 +00:00
Potherca-Bot
3c8a198738 Adds separate file for 'AttributeSubItem.php'. 2025-08-28 09:06:18 +00:00
Potherca-Bot
4205988f79 Changes content in separated file 'AttributeString.php'. 2025-08-28 09:06:17 +00:00
Potherca-Bot
517ef9f3cf Changes content in separated file 'AttributeStopWatch.php'. 2025-08-28 09:06:17 +00:00
Potherca-Bot
f6d94ec2b5 Adds separate file for 'AttributeString.php'. 2025-08-28 09:06:17 +00:00
Potherca-Bot
0d9210777c Adds separate file for 'AttributeStopWatch.php'. 2025-08-28 09:06:17 +00:00
Potherca-Bot
bd86e02872 Changes content in separated file 'AttributeSet.php'. 2025-08-28 09:06:16 +00:00
Potherca-Bot
095fed9d4c Changes content in separated file 'AttributeRedundancySettings.php'. 2025-08-28 09:06:16 +00:00
Potherca-Bot
734424aa8a Adds separate file for 'AttributeSet.php'. 2025-08-28 09:06:16 +00:00
Potherca-Bot
bf467f664c Changes content in separated file 'AttributeQueryAttCodeSet.php'. 2025-08-28 09:06:15 +00:00
Potherca-Bot
51d960a229 Adds separate file for 'AttributeRedundancySettings.php'. 2025-08-28 09:06:15 +00:00
Potherca-Bot
63d7a25982 Adds separate file for 'AttributeQueryAttCodeSet.php'. 2025-08-28 09:06:15 +00:00
Potherca-Bot
614cf7b3c8 Changes content in separated file 'AttributePropertySet.php'. 2025-08-28 09:06:14 +00:00
Potherca-Bot
ea20d30ad1 Changes content in separated file 'AttributePhoneNumber.php'. 2025-08-28 09:06:14 +00:00
Potherca-Bot
3fc16deed2 Adds separate file for 'AttributePropertySet.php'. 2025-08-28 09:06:14 +00:00
Potherca-Bot
78e51c1209 Adds separate file for 'AttributePhoneNumber.php'. 2025-08-28 09:06:14 +00:00
Potherca-Bot
b96ff56dfd Changes content in separated file 'AttributePercentage.php'. 2025-08-28 09:06:13 +00:00
Potherca-Bot
bdeed2a14c Changes content in separated file 'AttributePassword.php'. 2025-08-28 09:06:13 +00:00
Potherca-Bot
a63813f284 Adds separate file for 'AttributePercentage.php'. 2025-08-28 09:06:13 +00:00
Potherca-Bot
0ec54bccd2 Adds separate file for 'AttributePassword.php'. 2025-08-28 09:06:13 +00:00
Potherca-Bot
aa83d1160c Changes content in separated file 'AttributeOQL.php'. 2025-08-28 09:06:12 +00:00
Potherca-Bot
dab7fb6c53 Changes content in separated file 'AttributeOneWayPassword.php'. 2025-08-28 09:06:12 +00:00
Potherca-Bot
bdd188f9e8 Adds separate file for 'AttributeOQL.php'. 2025-08-28 09:06:12 +00:00
Potherca-Bot
6d1abd17a2 Adds separate file for 'AttributeOneWayPassword.php'. 2025-08-28 09:06:12 +00:00
Potherca-Bot
149fdbe9e4 Changes content in separated file 'AttributeObsolescenceFlag.php'. 2025-08-28 09:06:11 +00:00
Potherca-Bot
23ba1b41e3 Changes content in separated file 'AttributeObsolescenceDate.php'. 2025-08-28 09:06:11 +00:00
Potherca-Bot
c958f45433 Adds separate file for 'AttributeObsolescenceFlag.php'. 2025-08-28 09:06:11 +00:00
Potherca-Bot
506780ceed Changes content in separated file 'AttributeObjectKey.php'. 2025-08-28 09:06:10 +00:00
Potherca-Bot
bf2d70f952 Changes content in separated file 'AttributeMetaEnum.php'. 2025-08-28 09:06:10 +00:00
Potherca-Bot
73f2311ca4 Adds separate file for 'AttributeObsolescenceDate.php'. 2025-08-28 09:06:10 +00:00
Potherca-Bot
6c4e0c3718 Adds separate file for 'AttributeObjectKey.php'. 2025-08-28 09:06:10 +00:00
Potherca-Bot
28c4ebc7ea Changes content in separated file 'AttributeLongText.php'. 2025-08-28 09:06:09 +00:00
Potherca-Bot
d692e1562d Adds separate file for 'AttributeMetaEnum.php'. 2025-08-28 09:06:09 +00:00
Potherca-Bot
4284ed955b Adds separate file for 'AttributeLongText.php'. 2025-08-28 09:06:09 +00:00
Potherca-Bot
854290dd2d Changes content in separated file 'AttributeLinkedSet.php'. 2025-08-28 09:06:08 +00:00
Potherca-Bot
1cf995b0c1 Changes content in separated file 'AttributeLinkedSetIndirect.php'. 2025-08-28 09:06:08 +00:00
Potherca-Bot
284aa0a20f Adds separate file for 'AttributeLinkedSet.php'. 2025-08-28 09:06:08 +00:00
Potherca-Bot
a5887e20be Changes content in separated file 'AttributeIPAddress.php'. 2025-08-28 09:06:07 +00:00
Potherca-Bot
f0acbdf478 Changes content in separated file 'AttributeInteger.php'. 2025-08-28 09:06:07 +00:00
Potherca-Bot
8a2770cf13 Adds separate file for 'AttributeLinkedSetIndirect.php'. 2025-08-28 09:06:07 +00:00
Potherca-Bot
27c1a23ecf Adds separate file for 'AttributeIPAddress.php'. 2025-08-28 09:06:07 +00:00
Potherca-Bot
67089a6ad2 Changes content in separated file 'AttributeImage.php'. 2025-08-28 09:06:06 +00:00
Potherca-Bot
a711e39976 Adds separate file for 'AttributeInteger.php'. 2025-08-28 09:06:06 +00:00
Potherca-Bot
c1535f07fb Adds separate file for 'AttributeImage.php'. 2025-08-28 09:06:06 +00:00
Potherca-Bot
97ddb2e214 Changes content in separated file 'AttributeHTML.php'. 2025-08-28 09:06:05 +00:00
Potherca-Bot
a2adfe31d8 Changes content in separated file 'AttributeHierarchicalKey.php'. 2025-08-28 09:06:05 +00:00
Potherca-Bot
b3c4edc332 Changes content in separated file 'AttributeFriendlyName.php'. 2025-08-28 09:06:05 +00:00
Potherca-Bot
3b680a6f94 Adds separate file for 'AttributeHTML.php'. 2025-08-28 09:06:05 +00:00
Potherca-Bot
9e92a88cba Adds separate file for 'AttributeHierarchicalKey.php'. 2025-08-28 09:06:05 +00:00
Potherca-Bot
38dbae2bb6 Changes content in separated file 'AttributeFinalClass.php'. 2025-08-28 09:06:04 +00:00
Potherca-Bot
b830398ca3 Adds separate file for 'AttributeFriendlyName.php'. 2025-08-28 09:06:04 +00:00
Potherca-Bot
1e7d1c48c3 Adds separate file for 'AttributeFinalClass.php'. 2025-08-28 09:06:04 +00:00
Potherca-Bot
5bfe501bf4 Changes content in separated file 'AttributeExternalKey.php'. 2025-08-28 09:06:03 +00:00
Potherca-Bot
e55d12fae6 Changes content in separated file 'AttributeExternalField.php'. 2025-08-28 09:06:03 +00:00
Potherca-Bot
0d8857f989 Adds separate file for 'AttributeExternalKey.php'. 2025-08-28 09:06:03 +00:00
Potherca-Bot
81688e9c86 Adds separate file for 'AttributeExternalField.php'. 2025-08-28 09:06:03 +00:00
Potherca-Bot
51ceadd882 Changes content in separated file 'AttributeEnumSet.php'. 2025-08-28 09:06:02 +00:00
Potherca-Bot
71d2ed0402 Changes content in separated file 'AttributeEnum.php'. 2025-08-28 09:06:02 +00:00
Potherca-Bot
a09521ca6b Adds separate file for 'AttributeEnumSet.php'. 2025-08-28 09:06:02 +00:00
Potherca-Bot
17b2bb058d Changes content in separated file 'AttributeEncryptedString.php'. 2025-08-28 09:06:01 +00:00
Potherca-Bot
9433fbbfd1 Changes content in separated file 'AttributeEmailAddress.php'. 2025-08-28 09:06:01 +00:00
Potherca-Bot
ae5b9aac8a Adds separate file for 'AttributeEnum.php'. 2025-08-28 09:06:01 +00:00
Potherca-Bot
7088047a5e Adds separate file for 'AttributeEncryptedString.php'. 2025-08-28 09:06:01 +00:00
Potherca-Bot
b5d8740ab0 Changes content in separated file 'AttributeDuration.php'. 2025-08-28 09:06:00 +00:00
Potherca-Bot
e0e5b094a4 Adds separate file for 'AttributeEmailAddress.php'. 2025-08-28 09:06:00 +00:00
Potherca-Bot
9dc21cc91f Adds separate file for 'AttributeDuration.php'. 2025-08-28 09:06:00 +00:00
Potherca-Bot
99c16135c3 Changes content in separated file 'AttributeDefinition.php'. 2025-08-28 09:05:59 +00:00
Potherca-Bot
849f74147c Changes content in separated file 'AttributeDecimal.php'. 2025-08-28 09:05:59 +00:00
Potherca-Bot
3543115730 Changes content in separated file 'AttributeDeadline.php'. 2025-08-28 09:05:59 +00:00
Potherca-Bot
1f5c1df50c Adds separate file for 'AttributeDefinition.php'. 2025-08-28 09:05:59 +00:00
Potherca-Bot
d917a4cad3 Adds separate file for 'AttributeDecimal.php'. 2025-08-28 09:05:59 +00:00
Potherca-Bot
6bc96fb6eb Changes content in separated file 'AttributeDBFieldVoid.php'. 2025-08-28 09:05:58 +00:00
Potherca-Bot
22dbb0984d Adds separate file for 'AttributeDeadline.php'. 2025-08-28 09:05:58 +00:00
Potherca-Bot
5c5a184388 Adds separate file for 'AttributeDBFieldVoid.php'. 2025-08-28 09:05:58 +00:00
Potherca-Bot
3ee0b3a5e1 Changes content in separated file 'AttributeDBField.php'. 2025-08-28 09:05:57 +00:00
Potherca-Bot
16907d414e Changes content in separated file 'AttributeDateTime.php'. 2025-08-28 09:05:57 +00:00
Potherca-Bot
e928054e9c Adds separate file for 'AttributeDBField.php'. 2025-08-28 09:05:57 +00:00
Potherca-Bot
b5eb93dbd1 Adds separate file for 'AttributeDateTime.php'. 2025-08-28 09:05:57 +00:00
Potherca-Bot
31a4c38638 Changes content in separated file 'AttributeDate.php'. 2025-08-28 09:05:56 +00:00
Potherca-Bot
d6c73c8142 Changes content in separated file 'AttributeDashboard.php'. 2025-08-28 09:05:56 +00:00
Potherca-Bot
2ed9dc6f31 Adds separate file for 'AttributeDate.php'. 2025-08-28 09:05:56 +00:00
Potherca-Bot
fa51ef1adb Changes content in separated file 'AttributeCustomFields.php'. 2025-08-28 09:05:55 +00:00
Potherca-Bot
f2b2d422a6 Changes content in separated file 'AttributeClassState.php'. 2025-08-28 09:05:55 +00:00
Potherca-Bot
c58161b9b4 Adds separate file for 'AttributeDashboard.php'. 2025-08-28 09:05:55 +00:00
Potherca-Bot
0a32ddb8e2 Adds separate file for 'AttributeCustomFields.php'. 2025-08-28 09:05:55 +00:00
Potherca-Bot
161a05132b Changes content in separated file 'AttributeClass.php'. 2025-08-28 09:05:54 +00:00
Potherca-Bot
3967a82719 Changes content in separated file 'AttributeClassAttCodeSet.php'. 2025-08-28 09:05:54 +00:00
Potherca-Bot
ce9425f273 Adds separate file for 'AttributeClassState.php'. 2025-08-28 09:05:54 +00:00
Potherca-Bot
4af8f54f26 Adds separate file for 'AttributeClass.php'. 2025-08-28 09:05:54 +00:00
Potherca-Bot
bb904d7ec3 Changes content in separated file 'AttributeCaseLog.php'. 2025-08-28 09:05:53 +00:00
Potherca-Bot
426da64c46 Adds separate file for 'AttributeClassAttCodeSet.php'. 2025-08-28 09:05:53 +00:00
Potherca-Bot
6b4bfb0238 Adds separate file for 'AttributeCaseLog.php'. 2025-08-28 09:05:53 +00:00
Potherca-Bot
8420ef38ac Changes content in separated file 'AttributeBoolean.php'. 2025-08-28 09:05:52 +00:00
Potherca-Bot
db8f657c8e Changes content in separated file 'AttributeBlob.php'. 2025-08-28 09:05:52 +00:00
Potherca-Bot
a3d881715e Adds separate file for 'AttributeBoolean.php'. 2025-08-28 09:05:52 +00:00
Potherca-Bot
db9e932fc1 Adds separate file for 'AttributeBlob.php'. 2025-08-28 09:05:52 +00:00
Potherca-Bot
0cd9b08bcb Changes content in separated file 'AttributeArchiveFlag.php'. 2025-08-28 09:05:51 +00:00
Potherca-Bot
4b7d589c9f Changes content in separated file 'AttributeArchiveDate.php'. 2025-08-28 09:05:51 +00:00
Potherca-Bot
2554477987 Adds separate file for 'AttributeArchiveFlag.php'. 2025-08-28 09:05:51 +00:00
Potherca-Bot
3d0dc422dc Adds separate file for 'AttributeArchiveDate.php'. 2025-08-28 09:05:51 +00:00
Potherca-Bot
b469a16a05 Changes content in separated file 'AttributeApplicationLanguage.php'. 2025-08-28 09:05:50 +00:00
Potherca-Bot
995d6654fd Adds separate file for 'AttributeApplicationLanguage.php'. 2025-08-28 09:05:50 +00:00
anne-catherine
57892f58d8 end merge 2025-08-28 09:04:27 +00:00
anne-catherine
5c4def502c update asynctask.class.inc.php 2025-08-28 09:03:41 +00:00
Potherca-Bot
0d61f5ac6b Merge branch 'split-file_asynctask.class.inc.php_ExecAsyncTask.php' into split-file_asynctask.class.inc.php 2025-08-28 09:02:25 +00:00
Potherca-Bot
86cfe10e96 Merge branch 'split-file_asynctask.class.inc.php_AsyncTask.php' into split-file_asynctask.class.inc.php 2025-08-28 09:02:24 +00:00
Potherca-Bot
8042364a3b Merge branch 'split-file_asynctask.class.inc.php_AsyncSendNewsroom.php' into split-file_asynctask.class.inc.php 2025-08-28 09:02:24 +00:00
Potherca-Bot
9b29c45f2b Merge branch 'split-file_asynctask.class.inc.php_AsyncSendEmail.php' into split-file_asynctask.class.inc.php 2025-08-28 09:02:24 +00:00
Potherca-Bot
d10d5a6062 Changes content in separated file 'ExecAsyncTask.php'. 2025-08-28 09:02:23 +00:00
Potherca-Bot
cc38a03d17 Changes content in separated file 'AsyncTask.php'. 2025-08-28 09:02:23 +00:00
Potherca-Bot
e640443ea5 Adds separate file for 'ExecAsyncTask.php'. 2025-08-28 09:02:23 +00:00
Potherca-Bot
7f7cf50143 Adds separate file for 'AsyncTask.php'. 2025-08-28 09:02:23 +00:00
Potherca-Bot
3c639bdce3 Changes content in separated file 'AsyncSendNewsroom.php'. 2025-08-28 09:02:22 +00:00
Potherca-Bot
77448a7fc9 Changes content in separated file 'AsyncSendEmail.php'. 2025-08-28 09:02:22 +00:00
Potherca-Bot
41c2a9e97a Adds separate file for 'AsyncSendNewsroom.php'. 2025-08-28 09:02:22 +00:00
Potherca-Bot
080c72eec7 Adds separate file for 'AsyncSendEmail.php'. 2025-08-28 09:02:22 +00:00
anne-catherine
c8de4a4682 end merge 2025-08-28 08:59:06 +00:00
anne-catherine
c4d465574c update action.class.inc.php 2025-08-28 08:53:41 +00:00
Potherca-Bot
d776589fed Merge branch 'split-file_action.class.inc.php_Action.php' into split-file_action.class.inc.php 2025-08-28 08:48:41 +00:00
Potherca-Bot
22895462df Merge branch 'split-file_action.class.inc.php_ActionNotification.php' into split-file_action.class.inc.php 2025-08-28 08:48:40 +00:00
Potherca-Bot
34f4c4102d Changes content in separated file 'Action.php'. 2025-08-28 08:48:40 +00:00
Potherca-Bot
8c79499ace Merge branch 'split-file_action.class.inc.php_ActionEmail.php' into split-file_action.class.inc.php 2025-08-28 08:48:40 +00:00
Potherca-Bot
e7c62c9ef2 Changes content in separated file 'ActionNotification.php'. 2025-08-28 08:48:40 +00:00
Potherca-Bot
96154bd02d Adds separate file for 'Action.php'. 2025-08-28 08:48:40 +00:00
Potherca-Bot
6ecf784bc5 Changes content in separated file 'ActionEmail.php'. 2025-08-28 08:48:39 +00:00
Potherca-Bot
8748a1e51d Adds separate file for 'ActionNotification.php'. 2025-08-28 08:48:39 +00:00
Potherca-Bot
ffad7784aa Adds separate file for 'ActionEmail.php'. 2025-08-28 08:48:39 +00:00
anne-catherine
d4dc6c1860 Merge branch 'split-file_valuesetdef.class.inc.php' into feature/2535-split_file 2025-08-28 08:35:10 +00:00
anne-catherine
a1f92a1b4c update original file 2025-08-28 08:34:03 +00:00
Potherca-Bot
33a61a6daa Merge branch 'split-file_valuesetdef.class.inc.php_ValueSetRange.php' into split-file_valuesetdef.class.inc.php 2025-08-27 21:11:43 +00:00
Potherca-Bot
0ddd73bb36 Merge branch 'split-file_valuesetdef.class.inc.php_ValueSetObjects.php' into split-file_valuesetdef.class.inc.php 2025-08-27 21:11:43 +00:00
Potherca-Bot
a0a61837e7 Merge branch 'split-file_valuesetdef.class.inc.php_ValueSetEnum.php' into split-file_valuesetdef.class.inc.php 2025-08-27 21:11:43 +00:00
Potherca-Bot
b8d6990f17 Merge branch 'split-file_valuesetdef.class.inc.php_ValueSetEnumPadded.php' into split-file_valuesetdef.class.inc.php 2025-08-27 21:11:43 +00:00
Potherca-Bot
4b47eae92c Changes content in separated file 'ValueSetRange.php'. 2025-08-27 21:11:42 +00:00
Potherca-Bot
7dff1bb26f Changes content in separated file 'ValueSetObjects.php'. 2025-08-27 21:11:42 +00:00
Potherca-Bot
7e0e511b4b Changes content in separated file 'ValueSetEnum.php'. 2025-08-27 21:11:42 +00:00
Potherca-Bot
1e5cb01b15 Merge branch 'split-file_valuesetdef.class.inc.php_ValueSetEnumClasses.php' into split-file_valuesetdef.class.inc.php 2025-08-27 21:11:42 +00:00
Potherca-Bot
159496afd7 Adds separate file for 'ValueSetRange.php'. 2025-08-27 21:11:42 +00:00
Potherca-Bot
9178144675 Adds separate file for 'ValueSetObjects.php'. 2025-08-27 21:11:42 +00:00
Potherca-Bot
5264edb7ea Merge branch 'split-file_valuesetdef.class.inc.php_ValueSetDefinition.php' into split-file_valuesetdef.class.inc.php 2025-08-27 21:11:42 +00:00
Potherca-Bot
bcf05493d7 Changes content in separated file 'ValueSetEnumPadded.php'. 2025-08-27 21:11:41 +00:00
Potherca-Bot
599d34921f Adds separate file for 'ValueSetEnum.php'. 2025-08-27 21:11:41 +00:00
Potherca-Bot
f5646d6794 Changes content in separated file 'ValueSetEnumClasses.php'. 2025-08-27 21:11:41 +00:00
Potherca-Bot
842dce7c9c Changes content in separated file 'ValueSetDefinition.php'. 2025-08-27 21:11:41 +00:00
Potherca-Bot
cf15f087d4 Adds separate file for 'ValueSetEnumPadded.php'. 2025-08-27 21:11:41 +00:00
Potherca-Bot
376ec1763f Adds separate file for 'ValueSetEnumClasses.php'. 2025-08-27 21:11:41 +00:00
Potherca-Bot
45d29cf3b4 Adds separate file for 'ValueSetDefinition.php'. 2025-08-27 21:11:41 +00:00
Potherca-Bot
68d16625ce Merge branch 'split-file_event.class.inc.php_EventWebService.php' into split-file_event.class.inc.php 2025-08-27 20:39:13 +00:00
Potherca-Bot
412cef4893 Merge branch 'split-file_event.class.inc.php_EventRestService.php' into split-file_event.class.inc.php 2025-08-27 20:39:13 +00:00
Potherca-Bot
2f6980ab2b Merge branch 'split-file_event.class.inc.php_Event.php' into split-file_event.class.inc.php 2025-08-27 20:39:13 +00:00
Potherca-Bot
cab3705ed1 Changes content in separated file 'EventWebService.php'. 2025-08-27 20:39:12 +00:00
Potherca-Bot
69d33d03c8 Merge branch 'split-file_event.class.inc.php_EventOnObject.php' into split-file_event.class.inc.php 2025-08-27 20:39:12 +00:00
Potherca-Bot
9a7a4b6056 Merge branch 'split-file_event.class.inc.php_EventNotification.php' into split-file_event.class.inc.php 2025-08-27 20:39:12 +00:00
Potherca-Bot
b3b0c2966b Merge branch 'split-file_event.class.inc.php_EventNotificationEmail.php' into split-file_event.class.inc.php 2025-08-27 20:39:12 +00:00
Potherca-Bot
92b4e4bb94 Merge branch 'split-file_event.class.inc.php_EventLoginUsage.php' into split-file_event.class.inc.php 2025-08-27 20:39:12 +00:00
Potherca-Bot
3e28ec3cd4 Merge branch 'split-file_event.class.inc.php_EventIssue.php' into split-file_event.class.inc.php 2025-08-27 20:39:12 +00:00
Potherca-Bot
a4fae555c7 Changes content in separated file 'EventRestService.php'. 2025-08-27 20:39:11 +00:00
Potherca-Bot
dbc6b955b4 Changes content in separated file 'Event.php'. 2025-08-27 20:39:11 +00:00
Potherca-Bot
786be188e4 Adds separate file for 'EventWebService.php'. 2025-08-27 20:39:11 +00:00
Potherca-Bot
7821a9552d Changes content in separated file 'EventOnObject.php'. 2025-08-27 20:39:11 +00:00
Potherca-Bot
2377bd8eac Adds separate file for 'EventRestService.php'. 2025-08-27 20:39:11 +00:00
Potherca-Bot
3be8fa7a80 Adds separate file for 'Event.php'. 2025-08-27 20:39:11 +00:00
Potherca-Bot
12bdead661 Adds separate file for 'EventOnObject.php'. 2025-08-27 20:39:11 +00:00
Potherca-Bot
ad8d49a6af Changes content in separated file 'EventNotification.php'. 2025-08-27 20:39:10 +00:00
Potherca-Bot
0612903c7b Changes content in separated file 'EventNotificationEmail.php'. 2025-08-27 20:39:10 +00:00
Potherca-Bot
3c68bd0c37 Changes content in separated file 'EventLoginUsage.php'. 2025-08-27 20:39:10 +00:00
Potherca-Bot
7a178e9d9f Adds separate file for 'EventNotification.php'. 2025-08-27 20:39:10 +00:00
Potherca-Bot
1c643aa36c Adds separate file for 'EventNotificationEmail.php'. 2025-08-27 20:39:10 +00:00
Potherca-Bot
40c76eb36a Adds separate file for 'EventLoginUsage.php'. 2025-08-27 20:39:10 +00:00
Potherca-Bot
f5190a9dcd Changes content in separated file 'EventIssue.php'. 2025-08-27 20:39:09 +00:00
Potherca-Bot
254c4f5065 Adds separate file for 'EventIssue.php'. 2025-08-27 20:39:09 +00:00
2229 changed files with 125024 additions and 103676 deletions

101
.doc/README.md Normal file
View File

@@ -0,0 +1,101 @@
# Phpdoc dokuwiki template
This directory contains a template for rendering iTop phpdoc as dokuwiki pages.
Conventional tags that you should use:
* `@internal` : exclude from the documentation.
* `@api` : it means that a method is an api, thus it may be interacted with.
* `@see` : it points to another documented method
* `@link` : external url
* if you point to another page of the wiki, please use relative links.
* `@example` : let you provide example of code
* `@param`, `@return`, `@throws`, ...
## Special instructions
Some iTop specific tags were added :
* `@api-advanced`: it means that a method is an `@api` but mark it also as "complex" to use
* `@overwritable-hook`: used to mark a method as "designed to be extended"
* `@extension-hook`: not used for now
* `@phpdoc-tuning-exclude-inherited`: once this tag is present on a class, it's inherited methods won't be showed.
### known limitations:
#### `@see` tags must be very specific:
* always prefix class members (attributes or methods) with `ClassName::` (do not use self)
* for methods always suffix them with `()`,
* do not reference variables since they are not documented. If you have to, always prefix them with `$`
examples:
```
/**
* @see DBObject
* @see DBObject::Get()
* @see DBObject::$foo
*/
```
#### Do not use inline tags, they do not work properly, example:
```
/**
* This is a texts with an inline tag {@see [FQSEN] [<description>]} it must never be used
*/
```
#### The `@example` tag must respect this very precise syntax
* the sentence in the first line (next to the tag) is the title, it must be enclosed by double quotes
* the following lines are the sample code.
* 💔 since we simply hack the official tag, this syntax must be respected carefully 💔
example:
```
/**
* @example "This is the title of the multiline example"
* $foo = DBObject::Get('foo');
* DBObject::Set('foo', ++$foo);
*/
```
## How content is included into the documentation
**For a class** those requirements have to be respected:
- the file containing the class must be listed in `/phpdoc/files/file[]` of `.doc/phpdoc-objects-manipulation.dist.xml`
- the class **must not** have the tag `@internal`
- the class **must** have at least one of: `@api`, `@api-advanced`, `@overwritable-hook`, `@extension-hook`
Then, **for a method** of an eligible class:
- **public** methods **must** have at least one of: `@api`, `@api-advanced`, `@overwritable-hook`, `@extension-hook`
- **protected** methods **must** have at least one of: `@overwritable-hook`, `@extension-hook`
- **private** methods are **always excluded**
**Class properties** and **constants** are never documented (this is subject to change).
## A note about the rendering engine
:notebook: as spaces are used to mark code, the templates (`.doc/phpdoc-templates/combodo-wiki/*`) have very few indentation, thus they are awful to read (sorry).
## Installation
Note : PHP7 is required. Migrating to PHP8 requires some additional work which is questionable as an alternative way to generate a documentation is being considered.
```
cd .doc
composer require phpdocumentor/phpdocumentor:~2 --dev
```
## Generation
1. Switch to this directory : `cd /path/to/itop/.doc`
2. `composer install`
3. `./bin/build-doc-object-manipulation`
3. `./bin/build-doc-extensions`
4. Get the generated files from `/path/to/itop/data/phpdocumentor/output`
## Dokuwiki requirements
* the template uses the [wrap plugin](https://www.dokuwiki.org/plugin:wrap).
* the generated files have to be placed under an arbitrary directory of `[/path/to/dokuwiki]/data/pages`.
* the html has to be activated [config:htmlok](https://www.dokuwiki.org/config:htmlok)
* the generated files have to be in lowercase

6
.doc/bin/build-doc-extensions Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/sh -x
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf data/phpdocumentor/output/extensions/ && rm -rf data/phpdocumentor/temp/extensions/ && ./vendor/bin/phpdoc -c ./phpdoc-extensions.dist.xml -vvv
# now wee need to lowercase every generated file because dokuwiki can't handle uppercase
cd ../data/phpdocumentor/output/extensions/ && for i in $(ls | grep [A-Z]); do mv -i $i $(echo $i | tr 'A-Z' 'a-z'); done

View File

@@ -0,0 +1,7 @@
#!/bin/sh -x
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf ../data/phpdocumentor/output/objects-manipulation/ && rm -rf ../data/phpdocumentor/temp/objects-manipulation/ && ./vendor/bin/phpdoc -c ./phpdoc-objects-manipulation.dist.xml -vvv
# now wee need to lowercase every generated file because dokuwiki can't handle uppercase
cd ../data/phpdocumentor/output/objects-manipulation/ && for i in $( ls | grep [A-Z] ); do mv -i $i `echo $i | tr 'A-Z' 'a-z'`; done

6
.doc/composer.json Normal file
View File

@@ -0,0 +1,6 @@
{
"require-dev": {
"phpdocumentor/phpdocumentor": "~2",
"jms/serializer": "1.7.*"
}
}

3015
.doc/composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 MiB

View File

@@ -86,22 +86,19 @@ gitGraph
commit id: "2024-01-17a" tag: "2.7.10"
checkout support/3.0
commit id: "2024-01-17b" tag: "3.0.4"
checkout support/2.7
commit id: "2024-09-28" tag: "2.7.11"
checkout support/3.1
commit id: "2024-09-27" tag: "3.1.2"
checkout support/3.2
commit id: "2024-06-25" tag: "3.2.0-beta1" type: REVERSE
commit id: "2024-08-07" tag: "3.2.0"
commit id: "2024-09-13" tag: "3.2.0-2"
checkout support/3.1
commit id: "2024-09-27" tag: "3.1.2"
checkout support/2.7
commit id: "2024-09-28" tag: "2.7.11"
checkout support/2.7
commit id: "2025-02-25" tag: "2.7.12"
checkout support/3.1
commit id: "2025-02-25 " tag: "3.1.3"
checkout support/3.2
commit id: "2025-02-25 " tag: "3.2.1"
commit id: "2025-04-08" tag: "3.2.1-1"
commit id: "2025-08-19" tag: "3.2.2-1"
```
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).

20
.doc/phpdoc-extensions.dist.xml Executable file
View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<phpdoc>
<title><![CDATA[iTop extensions]]></title>
<parser>
<target>../data/phpdocumentor/temp/extensions</target>
</parser>
<transformer>
<target>../data/phpdocumentor/output/extensions</target>
</transformer>
<transformations>
<template name="phpdoc-templates/combodo-wiki"/>
</transformations>
<files>
<file>../application/applicationextension.inc.php</file>
</files>
</phpdoc>

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" ?>
<phpdoc>
<!--
/**
The documentation of this file can be found here : https://docs.phpdoc.org/references/configuration.html
it has to be completed by the CLI parameters documentation which is more comprehensive: https://docs.phpdoc.org/references/commands/project_run.html#usage
usage:
vendor/bin/phpdoc -c phpdoc-objects-manipulation.dist.xml
*/
-->
<title><![CDATA[iTop's objects manipulation API]]></title>
<parser>
<default-package-name>iTopORM</default-package-name>
<target>../data/phpdocumentor/temp/objects-manipulation</target>
<visibility>public,protected</visibility>
<markers>
<!--<item>TODO</item>-->
<!--<item>FIXME</item>-->
</markers>
<extensions>
<extension>php</extension>
</extensions>
</parser>
<transformer>
<target>../data/phpdocumentor/output/objects-manipulation</target>
</transformer>
<transformations>
<template name="phpdoc-templates/combodo-wiki"/>
</transformations>
<!--<logging>-->
<!--<level>warn</level>-->
<!--<paths>-->
<!--&lt;!&ndash;<default>data/phpdocumentor/log/objects-manipulation/{DATE}.log</default>&ndash;&gt;-->
<!--&lt;!&ndash;<errors>data/phpdocumentor/log/objects-manipulation/{DATE}.errors.log</errors>&ndash;&gt;-->
<!--<default>{APP_ROOT}/data/log/{DATE}.log</default>-->
<!--<errors>{APP_ROOT}/data/log/{DATE}.errors.log</errors>-->
<!--</paths>-->
<!--</logging>-->
<files>
<file>../core/dbobject.class.php</file>
<file>../core/dbobjectsearch.class.php</file>
<file>../core/metamodel.class.php</file>
<file>../core/dbobjectset.class.php</file>
<file>../core/dbsearch.class.php</file>
<file>../core/dbunionsearch.class.php</file>
</files>
</phpdoc>

View File

View File

@@ -0,0 +1,136 @@
{% extends 'layout.txt.twig' %}
{% block content %}
<wrap button>[[start|🔙 Back]]</wrap>
{% if node.tags['internal'] is defined %}
====== {{ node.name }} ======
<WRAP alert>This class is "internal", and thus is not documented!</WRAP>
{% elseif node.tags['api'] is not defined and node.tags['api-advanced'] is not defined and node.tags['overwritable-hook'] is not defined and node.tags['extension-hook'] is not defined %}
====== {{ node.name }} ======
<WRAP alert>This class is neither "api", "api-advanced", "overwritable-hook" or "extension-hook", and thus is not documented!</WRAP>
{% else %}
====== {{ node.name }} ======
{% if node.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
{% if node.abstract %}<wrap warning>abstract</wrap>{% endif %}
{% if node.final %}<wrap notice>final</wrap>{% endif %}
{% include 'includes/wrap-tags.txt.twig' with {structure:node, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
{% if node.deprecated %}
=== **<del>Deprecated</del>**===
//{{ node.tags.deprecated[0].description }}//
{% endif %}
== {{ node.summary|replace({"\n":""})|raw }} ==
<html>{{ node.description|markdown|raw }}</html>
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '====='} %}
{% set class = node.parent %}
{% block hierarchy_element %}
{% if class and class.name is defined and class.name|trim != '' %}
==== parent ====
{% set child = class %}
{% set class = class.parent %}
{{ block('hierarchy_element') }}
[[{{ child.name }}|{{ child.name }}]]
{% endif %}
{% endblock %}
{% for interface in node.interfaces|sort_asc %}
{% if loop.first %}
==== Implements ====
{% endif %}
{% if loop.length > 1 %} * {% endif %}{{ interface.fullyQualifiedStructuralElementName ?: interface }}
{% endfor %}
{% for trait in node.usedTraits|sort_asc %}
{% if loop.first %}
==== Uses traits ====
{% endif %}
{% if loop.length > 1 %} * {% endif %}{{ trait.fullyQualifiedStructuralElementName ?: trait }}
{% endfor %}
{% include 'includes/see-also.txt.twig' with {structure:node, title_level: '==='} %}
{% include 'includes/tags.txt.twig' with {structure:node, title_level: '=====', blacklist: ['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'phpdoc-tuning-exclude-inherited', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'copyright', 'license', 'code-example']} %}
{% set methods = node.inheritedMethods.merge(node.methods.merge(node.magicMethods)) %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api-advanced'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'overwritable-hook'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'extension-hook'} %}
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '=====', sub_title_level: '=='} %}
<WRAP clear />
{% for method in methods|sort_asc
if method.visibility == 'public'
and (
method.tags['api'] is defined
or method.tags['api-advanced'] is defined
or method.tags['overwritable-hook'] is defined
or method.tags['extension-hook'] is defined
)
and (
node.tags['phpdoc-tuning-exclude-inherited'] is not defined
or method.parent.name == node.name
)
%}
{%- if loop.first %}
===== Public methods =====
{% endif %}
{{ block('method') }}
{% endfor %}
{% for method in methods|sort_asc if method.visibility == 'protected' and (method.tags['overwritable-hook'] is defined or method.tags['extension-hook'] is defined) %}
{%- if loop.first %}
===== Protected methods =====
{% endif %}
{{ block('method') }}
{% endfor %}
{% set constants = node.inheritedConstants.merge(node.constants) %}
{% if constants|length > 0 %}
===== Constants =====
{% for constant in constants|sort_asc %}
{{ block('constant') }}
{% endfor %}
{% endif %}
{#{% set properties = node.inheritedProperties.merge(node.properties.merge(node.magicProperties)) %}#}
{#{% for property in properties|sort_asc if property.visibility == 'public' %}#}
{#{%- if loop.first %}#}
{#===== Public properties =====#}
{#{% endif %}#}
{#{{ block('property') }}#}
{#{% endfor %}#}
{#{% for property in properties|sort_asc if property.visibility == 'protected' %}#}
{#{%- if loop.first %}#}
{#===== Protected properties =====#}
{#{% endif %}#}
{#{{ block('property') }}#}
{#{% endfor %}#}
{%- endif %} {#{% elseif node.tags['xxx'] is not defined and ... #}
<wrap button>[[start|🔙 Back]]</wrap>
{% endblock %}

View File

@@ -0,0 +1,31 @@
{% block constant %}
<WRAP group box >
<WRAP twothirds column >
==== {{ constant.name }} ====
</WRAP>{# twothirds column#}
<WRAP third column>
{% if constant.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
{% if (node.parent is not null and constant.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
</WRAP>{# third column#}
== {{ constant.summary|replace({"\n":""})|raw }} ==
<html>{{ constant.description|markdown|raw }}</html>
{% if constant.deprecated %}
=== Deprecated ===
{{ constant.tags.deprecated[0].description|raw }}
{% endif %}
{% include 'includes/inherited-from.txt.twig' with {structure:constant} %}
{% include 'includes/see-also.txt.twig' with {structure:constant, title_level: '=='} %}
{% include 'includes/uses.txt.twig' with {structure:constant, title_level: '=='} %}
{% include 'includes/tags.txt.twig' with {structure:constant, title_level: '==', blacklist: ['link', 'see', 'var', 'deprecated', 'uses', 'package', 'subpackage', 'todo', 'code-example']} %}
</WRAP>{# group #}
{% endblock %}

View File

@@ -0,0 +1,95 @@
{% block method %}
<WRAP group box >
<WRAP twothirds column >
==== {{ method.name }} ====
</WRAP>{# twothirds column#}
<WRAP third column >
{% include 'includes/wrap-tags.txt.twig' with {structure:method, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
{% if method.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
{% if (node.parent is not null and method.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
{% if method.abstract %}<wrap warning>abstract</wrap> {% endif %}
{% if method.final %}<wrap notice>final</wrap> {% endif %}
<wrap notice>{{ method.visibility }}</wrap>
{% if method.static %}<wrap warning>static</wrap> {% endif %}
</WRAP>{# third column#}
== {{ method.summary|replace({"\n":""})|raw }} ==
<html>{{ method.description|markdown|raw }}</html>
<code php>{% if method.abstract %}abstract {% endif %}{% if method.final %}final {% endif %}{{ method.visibility }} {% if method.static %}static {% endif %}{{ method.name }}({% for argument in method.arguments %}{{ argument.isVariadic ? '...' }}{{ argument.name }}{{ argument.default ? (' = '~argument.default)|raw }}{% if not loop.last %}, {% endif %}{% endfor %})</code>
<WRAP twothirds column >
=== Parameters ===
{% if method.arguments|length > 0 -%}
^ types ^ name ^ default ^ description ^
{% for argument in method.arguments -%}
| **<nowiki>{{ argument.types|join('|')|raw }}</nowiki>** | {{ argument.name }} {{ argument.isVariadic ? '<small style="color: gray">variadic</small>' }} | <nowiki>{{ argument.default|raw }}</nowiki> | {{ argument.description|trim|replace("\n", ' ')|raw }} |{{ "\r\n" }}
{%- endfor %}
{% else %}
//none//
{% endif %}
{#=== Parameters ===#}
{#{% if method.arguments|length > 0 -%}#}
{#{% for argument in method.arguments -%}#}
{#== {{ argument.name }} ==#}
{#{% set varDesc %}#}
{#<span style="margin:0 10px; 0 20px; font-weight: bold;">{{ argument.types|join('|') }}</span>#}
{#{{ argument.isVariadic ? '<small style="color: gray">variadic</small>' }}#}
{#{{ argument.description|raw }}#}
{#{% endset %}#}
{#<html>{{ varDesc|markdown|raw }}</html>#}
{#{%- endfor %}#}
{#{% else %}#}
{#<wrap tip>This method has no parameter</wrap>#}
{#{% endif %}#}
{% if method.response and method.response.types|join() != 'void' %}
=== Returns ===
<html>{{ ('**' ~ method.response.types|join('|')|trim ~ '** ' ~ method.response.description)|markdown|raw }}</html>
{% endif %}
</WRAP>{# twothirds column#}
<WRAP third column >
{% if method.tags.throws|length > 0 or method.tags.throw|length > 0 %}
=== Throws ===
{% for exception in method.tags.throws -%}
{% if loop.length > 1 %} * {% endif %}''{{ exception.types|join('|')|raw }}'' <nowiki>{{ exception.description|raw }}</nowiki>
{% endfor %}
{% endif %}
{% include 'includes/inherited-from.txt.twig' with {structure:method} %}
{% include 'includes/see-also.txt.twig' with {structure:method, title_level: '==='} %}
{% include 'includes/uses.txt.twig' with {structure:method, title_level: '==='} %}
{% include 'includes/used-by.txt.twig' with {structure:method, title_level: '==='} %}
{% include 'includes/tags-with-description.txt.twig' with {structure:method, title_level: '===', WRAP: 'info', tagsWithDescription: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
{% include 'includes/tags.txt.twig' with {structure:method, title_level: '===', blacklist: ['todo', 'link', 'see', 'abstract', 'example', 'param', 'return', 'access', 'deprecated', 'throws', 'throw', 'uses', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'used-by', 'inheritdoc', 'code-example']} %}
</WRAP>{# third column#}
{% include 'includes/code-examples.txt.twig' with {structure:method, title_level: '==='} %}
</WRAP>{# group #}
{% endblock %}

View File

@@ -0,0 +1,49 @@
{% block property %}
<WRAP group box>
<WRAP twothirds column >
==== ${{ property.name }} ====
</WRAP>{# twothirds column#}
<WRAP third column>
{% if property.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
{% if (node.parent is not null and property.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
</WRAP>{# third column#}
== {{ property.summary|replace({"\n":""})|raw }} ==
<html>{{ property.description|markdown|raw }}</html>
{% if property.var.0.description %}<html>{{ property.var.0.description|markdown|raw }}</html>{% endif %}
{#{% if property.types %}#}
{#== Type ==#}
{#{% for type in property.types %}#}
{#{% if loop.length > 1 %} * {% endif %}{{ type|raw }} : {{ type.description|raw }}#}
{#{% endfor %}#}
{#{{ property.types|join('|')|raw }}#}
{#{% endif %}#}
{% if property.deprecated %}
== Deprecated ==
{{ property.tags.deprecated[0].description }}
{% endif %}
{% include 'includes/inherited-from.txt.twig' with {structure:property} %}
{% include 'includes/see-also.txt.twig' with {structure:property, title_level: '=='} %}
{% include 'includes/uses.txt.twig' with {structure:property, title_level: ''} %}
{% include 'includes/tags.txt.twig' with {structure:property, title_level: '==', blacklist: ['link', 'see', 'access', 'var', 'deprecated', 'uses', 'todo', 'code-example']} %}
<code php>{{ property.visibility }} ${{ property.name }}{% if property.types %} : {{ property.types|join('|')|raw }}{% endif %}</code>
</WRAP>{# group #}
{% endblock %}

View File

@@ -0,0 +1 @@
{{ node.source|raw }}

View File

@@ -0,0 +1,122 @@
{% extends 'layout.txt.twig' %}
{% block javascripts %}
{% endblock %}
{% block content %}
{#<section class="row-fluid">#}
{#<div class="span2 sidebar">#}
{#{% set namespace = project.namespace %}#}
{#{{ block('sidebarNamespaces') }}#}
{#</div>#}
{#</section>#}
{#<section class="row-fluid">#}
====== {{ node.path|split('/')|slice(0,-1)|join('/') }}{{ node.name }} ======
{{ node.summary }}
<html>{{ node.description|markdown|raw }}</html>
{% if node.traits|length > 0 %}
===== Traits =====
{% for trait in node.traits %}
<tr>
<td>{{ trait|raw }}</td>
<td><em>{{ trait.summary }}</em></td>
</tr>
{% endfor %}
{% endif %}
{% if node.interfaces|length > 0 %}
===== Interfaces =====
{% for interface in node.interfaces %}
<tr>
<td>{{ interface|raw }}</td>
<td><em>{{ interface.summary }}</em></td>
</tr>
{% endfor %}
{% endif %}
{% if node.classes|length > 0 %}
===== Classes =====
{% for class in node.classes %}
{{ class|raw }}
<em>{{ class.summary }}</em>
{% endfor %}
{% endif %}
{% if node.package is not empty and node.package != '\\' %}
===== Package =====
{{ node.subpackage ? (node.package ~ '\\' ~ node.subpackage) : node.package }}
{% endif %}
{% for tagName,tags in node.tags if tagName in ['link', 'see'] %}
{% if loop.first %}
===== See also =====
{% endif %}
{% for tag in tags %}
<dd><a href="{{ tag.reference ?: tag.link }}"><div class="namespace-wrapper">{{ tag.description ?: tag.reference }}</div></a></dd>
{% endfor %}
{% endfor %}
<h2>Tags</h2>
<table class="table table-condensed">
{% for tagName,tags in node.tags if tagName not in ['link', 'see', 'package', 'subpackage'] %}
<tr>
<th>
{{ tagName }}
</th>
<td>
{% for tag in tags %}
{{ tag.description|markdown|raw }}
{% endfor %}
</td>
</tr>
{% else %}
<tr><td colspan="2"><em>None found</em></td></tr>
{% endfor %}
</table>
</aside>
</div>
{% if node.constants|length > 0 %}
<div class="row-fluid">
<section class="span8 content file">
<h2>Constants</h2>
</section>
<aside class="span4 detailsbar"></aside>
</div>
{% for constant in node.constants %}
{{ block('constant') }}
{% endfor %}
{% endif %}
{% if node.functions|length > 0 %}
<div class="row-fluid">
<section class="span8 content file">
<h2>Functions</h2>
</section>
<aside class="span4 detailsbar"></aside>
</div>
{% for method in node.functions %}
{{ block('method') }}
{% endfor %}
{% endif %}
</div>
</section>
<div id="source-view" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="source-view-label" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="source-view-label">{{ node.file.name }}</h3>
</div>
<div class="modal-body">
<pre data-src="{{ path('files/' ~ node.path ~ '.txt')|raw }}" class="language-php line-numbers"></pre>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,42 @@
{% extends 'layout.html.twig' %}
{% block stylesheets %}
<link href="{{ path('css/jquery.iviewer.css') }}" rel="stylesheet" media="all"/>
<style>
#viewer {
position: relative;
width: 100%;
}
.wrapper {
overflow: hidden;
}
</style>
{% endblock %}
{% block javascripts %}
<script src="{{ path('js/jquery.mousewheel.js') }}" type="text/javascript"></script>
<script src="{{ path('js/jquery.iviewer.js') }}" type="text/javascript"></script>
<script type="text/javascript">
$(window).resize(function(){
$("#viewer").height($(window).height() - 100);
});
$(document).ready(function() {
$("#viewer").iviewer({src: '{{ path('graphs/classes.svg') }}', zoom_animation: false});
$('#viewer img').on('dragstart', function(event){
event.preventDefault();
});
$(window).resize();
});
</script>
{% endblock %}
{% block content %}
<div class="row-fluid">
<div class="span12">
<div class="wrapper">
<div id="viewer" class="viewer"></div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,5 @@
# Fixes a vulnerability in CentOS: http://stackoverflow.com/questions/20533279/prevent-php-from-parsing-non-php-files-such-as-somefile-php-txt
<FilesMatch \.php\.txt$>
RemoveHandler .php
ForceType text/plain
</FilesMatch>

View File

@@ -0,0 +1,34 @@
{% if title_level is not defined %}
{%- set title_level = '==' -%}
{% endif %}
{% if sub_title_level is not defined %}
{%- set sub_title_level = title_level|slice(1) -%}
{% endif %}
{% if sub_title_level == '=' %}
{%- set sub_title_level = '' -%}
{% endif %}
{#{% for tagName,tags in structure.tags if tagName in ['code-example'] %}#}
{#{% if loop.first %}#}
{#{{title_level}} Examples {{title_level}}#}
{#{% endif %}#}
{#{% for tag in tags %}#}
{#{%- set descToken = tag.description|split("\n", 2) -%}#}
{#{%- set title = descToken[0] -%}#}
{#{%- set code = descToken[1] -%}#}
{#{{sub_title_level}} {{ title }} {{sub_title_level}}#}
{#<code php>{{ code|raw }}</code>#}
{#{% endfor %}#}
{#{% endfor %}#}
{% for tagName,tags in structure.tags if tagName in ['example'] %}
{% if loop.first %}
{{title_level}} Examples {{title_level}}
{% endif %}
{% for tag in tags %}
{{ sub_title_level }} {{ tag.filePath|escape }}{{ sub_title_level }}
<code php>{{ tag.description|raw }}</code>
{% endfor %}
{% endfor %}

View File

@@ -0,0 +1,12 @@
{% if title_level is not defined %}
{% set title_level='' %}
{% endif %}
{% if (node.parent is null) %}
{{title_level}} File {{ structure.path }} {{title_level}}
{% endif %}
{% if (node.parent is not null and structure.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}
{{title_level}} Inherited from {{title_level}}
[[{{structure.parent}}|{{structure.parent}}]]
{% endif %}

View File

@@ -0,0 +1,26 @@
{% for structure in structures|sort_asc if structure.tags['internal'] is not defined and (structure.tags['api'] is defined or structure.tags['api-advanced'] is defined or structure.tags['overwritable-hook'] is defined or structure.tags['extension-hook'] is defined ) %}
{#{{ structure|raw }}#}
{% set structureName = structure|trim('\\', 'left') %}
<WRAP group box>
<WRAP twothirds column >
==== {{ structureName }} ====
</WRAP>{# twothirds column#}
<WRAP third column>
{% if structure.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
{% if structure.abstract %}<wrap warning>abstract</wrap>{% endif %}
{% if structure.final %}<wrap notice>final</wrap>{% endif %}
{% if (node.parent is not null and structure.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
{% include 'includes/wrap-tags.txt.twig' with {structure:structure, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
</WRAP>{# third column#}
{{ structure.summary|raw }}
[[{{structureName}}|More information]]
</WRAP>{# group #}
{% endfor %}

View File

@@ -0,0 +1,26 @@
{% if title_level is not defined %}
{%- set title_level='==' -%}
{% endif %}
{% for tagName,tags in structure.tags if tagName in ['link', 'see'] %}
{% if loop.first %}
{{title_level}} See also {{title_level}}
{% endif %}
{% for tag in tags %}
{%- set linkTag = tag.reference|trim('\\', 'left') -%}
{% if not('()' in linkTag or '$' in linkTag or node.name in linkTag or '::' in linkTag ) %}
{%- set linkTag = linkTag|lower -%}
{% elseif node.name~'::' in linkTag %}
{%- set linkTag = linkTag|replace({(node.name~'::'): '#'})|lower -%}
{% elseif '::' in linkTag -%}
{%- set linkTag = linkTag|replace({'::': '#'})|lower -%}
{% else %}
{%- set linkTag = '#' ~ linkTag|lower -%}
{%- endif %}
{% if loop.length > 1 %} * {% endif %}{% if tag.reference is not empty -%}
[[{{linkTag}}|{{ (tag.reference)|trim('\\', 'left') }}]] {% if tag.description|trim is not empty %}: {{ tag.description|trim('\\', 'left') }} {% endif %}
{%- else -%}
{#{{ tag.description|trim('\\', 'left') }}#}
{% endif %}
{% endfor %}
{% endfor %}

View File

@@ -0,0 +1,56 @@
{% if tag is not defined -%}
{# Do not display @api if @api-advanced is also present #}
{%- set tag = "api" -%}
{%- endif %}
{% if hidden_by is not defined -%}
{# Do not display @api if @api-advanced is also present #}
{%- set hidden_by = {"api" : "api-advanced"} -%}
{%- endif %}
{% for method in methods|sort_asc
if (method.visibility == 'public')
and (
method.tags[tag] is defined
and (
hidden_by[tag] is not defined or method.tags[hidden_by[tag]] is not defined
)
)
%}
{%- if loop.first %}
{% if tag == 'api' %}
===== API synthesis =====
<WRAP>
List of the public API methods.
When manipulating {{ node.name }}, You can call those methods:
</WRAP>
{% elseif tag == 'api-advanced' %}
===== Advanced API synthesis =====
<WRAP>
List of advanced API methods
Beware they usage is recommended to advanced users only.
</WRAP>
{% elseif tag == 'overwritable-hook' %}
===== overwritable-hook synthesis =====
<WRAP >When inheriting from {{ node.name }},
you can overwrite those methods in order to add custom logic:
</WRAP>
{% elseif tag == 'extension-hook' %}
===== extension-hook synthesis =====
<WRAP >
When inheriting from {{ node.name }},
you can extend the behaviour of iTop by implementing:
</WRAP>
{% endif %}
{% endif %}
{% set sanitizedMethod = method|trim('\\', 'left')|replace({(node.name~'::'): ''}) %}
{% if '::' in sanitizedMethod -%}
{%- if node.tags['phpdoc-tuning-exclude-inherited'] is not defined %}
* [[{{sanitizedMethod|replace({'::': '#'})|lower}}|↪{{sanitizedMethod}}]] — {{ method.summary|replace({"\n":""})|raw }}
{% endif %}
{%- else %}
* [[#{{sanitizedMethod}}|{{sanitizedMethod}}]] — {{ method.summary|replace({"\n":""})|raw }}
{% endif %}
{% endfor %}

View File

@@ -0,0 +1,20 @@
{% if title_level is not defined %}
{% set title_level = '==' %}
{% endif %}
{%- for tagName,tags in structure.tags if tagName in tagsWithDescription -%}
{%- for tag in tags -%}
{%- if tag.description is not empty -%}
{%- if WRAP is defined -%}
<WRAP {{WRAP}}>
{%- endif -%}
{{title_level}} {{ tagName }} {{title_level}}
{{ tag.description|escape }}
{%- if WRAP is defined -%}
</WRAP>
{%- endif -%}
{%- endif -%}
{%- endfor -%}
{%- endfor -%}

View File

@@ -0,0 +1,22 @@
{% if title_level is not defined %}
{% set title_level='=====' %}
{% endif %}
{% if blacklist is not defined %}
{% set blacklist =['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'api', 'api-advanced', 'todo', 'code-example'] %}
{% endif %}
{% if hidden_by is not defined -%}
{# Do not display @api if @api-advanced is also present #}
{%- set hidden_by = {"api" : "api-advanced"} -%}
{%- endif %}
{#^ {% for tagName,tags in structure.tags if tagName not in blacklist -%}#}
{#{{ tagName }} ^#}
{#{%- endfor %}#}
{% for tagName,tags in structure.tags if tagName not in blacklist and (hidden_by[tagName] is not defined or structure.tags[hidden_by[tagName]] is not defined) %}
{%- if loop.first %}
{{title_level}} Tags {{title_level}}
{% endif %}
^ {{ tagName }} | {% for tag in tags %}{{ tag.version ? tag.version ~ ' ' : '' }}{{ tag.description}}{% endfor %} |
{% endfor %}

View File

@@ -0,0 +1,24 @@
{% if title_level is not defined %}
{% set title_level='' %}
{% endif %}
{% for tagName,tags in structure.tags if tagName in ['used-by'] %}
{% if loop.first %}
{{title_level}} Used by {{title_level}}
{% endif %}
{% for tag in tags %}
{% if loop.length > 1 %} * {% endif %}{{ tag.reference ?: tag.link }} : {{ tag.description ?: tag.reference }}
{% endfor %}
{% endfor %}
{#{% for tagName,tags in method.tags if tagName in ['uses'] %}#}
{#{% if loop.first %}#}
{#<dt>Uses</dt>#}
{#{% endif %}#}
{#{% for tag in tags %}#}
{#<dd>{{ tag.reference|raw }}</dd>#}
{#{% endfor %}#}
{#{% endfor %}#}

View File

@@ -0,0 +1,24 @@
{% if title_level is not defined %}
{% set title_level='' %}
{% endif %}
{% for tagName,tags in structure.tags if tagName in ['uses'] %}
{% if loop.first %}
{{title_level}} Uses {{title_level}}
{% endif %}
{% for tag in tags %}
{% if loop.length > 1 %} * {% endif %}{{ tag.reference ?: tag.link }} : {{ tag.description ?: tag.reference }}
{% endfor %}
{% endfor %}
{#{% for tagName,tags in method.tags if tagName in ['uses'] %}#}
{#{% if loop.first %}#}
{#<dt>Uses</dt>#}
{#{% endif %}#}
{#{% for tag in tags %}#}
{#<dd>{{ tag.reference|raw }}</dd>#}
{#{% endfor %}#}
{#{% endfor %}#}

View File

@@ -0,0 +1,11 @@
{% if wrap is not defined -%}
{% set wrap = 'notice' %}
{%- endif -%}
{% if hidden_by is not defined -%}
{# Do not display @api if @api-advanced is also present #}
{%- set hidden_by = {"api" : "api-advanced"} -%}
{%- endif %}
{%- for tagName,tags in structure.tags if tagName in wrapTags and (hidden_by[tagName] is not defined or structure.tags[hidden_by[tagName]] is not defined) %}
<wrap {{wrap}}>{{tagName}}</wrap>
{% endfor %}

View File

@@ -0,0 +1,121 @@
{% extends 'layout.txt.twig' %}
{% block content %}
<wrap button>[[start|🔙 Back]]</wrap>
{% if node.tags['internal'] is defined %}
====== {{ node.name }} ======
<WRAP alert>This interface is "internal", and thus is not documented!</WRAP>
{% elseif node.tags['api'] is not defined and node.tags['api-advanced'] is not defined and node.tags['overwritable-hook'] is not defined and node.tags['extension-hook'] is not defined %}
====== {{ node.name }} ======
<WRAP alert>This interface is neither "api", "overwritable-hook" or "extension-hook", and thus is not documented!</WRAP>
{% else %}
====== {{ node.name }} ======
{% if node.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
{% if node.abstract %}<wrap warning>abstract</wrap>{% endif %}
{% if node.final %}<wrap notice>final</wrap>{% endif %}
{% include 'includes/wrap-tags.txt.twig' with {structure:node, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
{% if node.deprecated %}
=== **<del>Deprecated</del>**===
//{{ node.tags.deprecated[0].description }}//
{% endif %}
== {{ node.summary|replace({"\n":""})|raw }} ==
<html>{{ node.description|markdown|raw }}</html>
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '====='} %}
{% set class = node.parent %}
{% block hierarchy_element %}
{% if class and class.name is defined and class.name|trim != '' %}
==== parent ====
{% set child = class %}
{% set class = class.parent %}
{{ block('hierarchy_element') }}
[[{{ child.name }}|{{ child.name }}]]
{% endif %}
{% endblock %}
{% for interface in node.interfaces|sort_asc %}
{% if loop.first %}
==== Implements ====
{% endif %}
{% if loop.length > 1 %} * {% endif %}{{ interface.fullyQualifiedStructuralElementName ?: interface }}
{% endfor %}
{% for trait in node.usedTraits|sort_asc %}
{% if loop.first %}
==== Uses traits ====
{% endif %}
{% if loop.length > 1 %} * {% endif %}{{ trait.fullyQualifiedStructuralElementName ?: trait }}
{% endfor %}
{% include 'includes/see-also.txt.twig' with {structure:node, title_level: '==='} %}
{% include 'includes/tags.txt.twig' with {structure:node, title_level: '=====', blacklist: ['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'phpdoc-tuning-exclude-inherited', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'copyright', 'license', 'code-example']} %}
{% set methods = node.inheritedMethods.merge(node.methods) %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api-advanced'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'overwritable-hook'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'extension-hook'} %}
<WRAP clear />
{% for method in methods|sort_asc if method.visibility == 'public' %}
{%- if loop.first %}
===== Public methods =====
{% endif %}
{{ block('method') }}
{% endfor %}
{% for method in methods|sort_asc if method.visibility == 'protected' %}
{%- if loop.first %}
===== Protected methods =====
{% endif %}
{{ block('method') }}
{% endfor %}
{% set constants = node.inheritedConstants.merge(node.constants) %}
{% if constants|length > 0 %}
===== Constants =====
{% for constant in constants|sort_asc %}
{{ block('constant') }}
{% endfor %}
{% endif %}
{#{% set properties = node.inheritedProperties.merge(node.properties) %}#}
{#{% for property in properties|sort_asc if property.visibility == 'public' %}#}
{#{%- if loop.first %}#}
{#===== Public properties =====#}
{#{% endif %}#}
{#{{ block('property') }}#}
{#{% endfor %}#}
{#{% for property in properties|sort_asc if property.visibility == 'protected' %}#}
{#{%- if loop.first %}#}
{#===== Protected properties =====#}
{#{% endif %}#}
{#{{ block('property') }}#}
{#{% endfor %}#}
{%- endif %} {#{% elseif node.tags['xxx'] is not defined and ... #}
<wrap button>[[start|🔙 Back]]</wrap>
{% endblock %}

View File

@@ -0,0 +1,5 @@
{% use 'elements/constant.txt.twig' %}
{% use 'elements/property.txt.twig' %}
{% use 'elements/method.txt.twig' %}
{% block content %}{% endblock %}

View File

@@ -0,0 +1,51 @@
{% extends 'layout.txt.twig' %}
{% block content %}
{% set namespace = project.namespace %}
{{ block('sidebarNamespaces') }}
{#{{ node.parent|raw }}#}
{#====== {{ node.parent.fullyQualifiedStructuralElementName }}{{ node.name }} ======#}
{% if node.children|length > 0 %}
=====Namespaces=====
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.children} %}
----
{% endif %}
{% if node.traits|length > 0 %}
===== Traits =====
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.traits} %}
----
{%- endif %}
{% if node.interfaces|length > 0 %}
===== Interfaces =====
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.interfaces} %}
----
{% endif %}
{% if node.classes|length > 0 %}
===== Classes =====
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.classes} %}
----
{% endif %}
{#{% if node.constants|length > 0 %}#}
{#===== Constants =====#}
{#{% for constant in node.constants|sort_asc %}#}
{# {{ block('constant') }}#}
{#{% endfor %}#}
{#{% endif %}#}
{#{% if node.functions|length > 0 %}#}
{#===== Functions =====#}
{#{% for method in node.functions|sort_asc %}#}
{# {{ block('method') }}#}
{#{% endfor %}#}
{#{% endif %}#}
{% endblock %}

View File

@@ -0,0 +1,49 @@
====== Deprecated elements ======
{#{% for element in project.indexes.elements if element.deprecated %}#}
{#{% if element.file.path != previousPath %}#}
{#<li><a href="#{{ element.file.path }}"><i class="icon-file"></i> {{ element.file.path }}</a></li>#}
{#{% endif %}#}
{#{% set previousPath = element.file.path %}#}
{#{% endfor %}#}
{% for element in project.indexes.elements if element.deprecated %}
{% if element.file.path != previousPath %}
{% if previousPath %}
</WRAP>{# group #}
{% endif %}
{#<a name="{{ element.file.path }}" id="{{ element.file.path }}"></a>#}
===== {{ element.file.path }} ({{ element.tags.deprecated.count }} found)=====
<WRAP group >
<WRAP third column >
Element
</WRAP>{# third column#}
<WRAP third column >
Line
</WRAP>{# third column#}
<WRAP third column >
Description
</WRAP>{# third column#}
{% endif %}
{% for tag in element.tags.deprecated %}
<WRAP group >
<WRAP third column >
{{ element.fullyQualifiedStructuralElementName }}
</WRAP>{# third column#}
<WRAP third column >
{{ element.line }}
</WRAP>{# third column#}
<WRAP third column >
{{ tag.description }}
</WRAP>{# third column#}
{% endfor %}
</WRAP>{# group #}
{% set previousPath = element.file.path %}
{% else %}
<WRAP info>No deprecated elements have been found in this project.</WRAP>
{% endfor %}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<template>
<author>Bruno DA SILVA</author>
<email>contact [at] combodo.com</email>
<version>1.0.0</version>
<copyright>Combodo 2018</copyright>
<description><![CDATA[
Forked from the clean theme of https://github.com/phpDocumentor/phpDocumentor2 provided under the MIT licence.
The original work is copyright "Mike van Riel".
------------------------------------------------------------------------------------------------------------------
To improve performance you can add the following to your .htaccess:
<ifModule mod_deflate.c>
<filesMatch "\.(js|css|html)$">
SetOutputFilter DEFLATE
</filesMatch>
</ifModule>
]]></description>
<transformations>
<transformation writer="twig" query="namespace" source="templates/combodo-wiki/namespace.txt.twig" artifact="start.txt"/>
<transformation writer="twig" query="indexes.classes" source="templates/combodo-wiki/class.txt.twig" artifact="{{name}}.txt"/>
<transformation writer="twig" query="indexes.interfaces" source="templates/combodo-wiki/interface.txt.twig" artifact="{{name}}.txt" />
</transformations>
</template>

View File

@@ -53,7 +53,7 @@ iTop also offers mass import tools to help you become even more efficient.
[4]: https://www.itophub.io/wiki/page?id=latest:install:requirements
[5]: https://www.itophub.io/wiki
[6]: https://store.itophub.io/en_US/
[7]: itop-version-history.md
[7]: .doc/itop-version-history.md
[10]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#configuration_management_cmdb
[11]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#ticketing

View File

@@ -57,6 +57,12 @@ require_once(APPROOT.'application/applicationextension/backoffice/SeparatorPopup
require_once(APPROOT.'application/applicationextension/backoffice/URLButtonItem.php');
require_once(APPROOT.'application/applicationextension/backoffice/URLPopupMenuItem.php');
//deprecated class and interface
require_once(APPROOT.'application/applicationextension/backoffice/iApplicationObjectExtension.php');
require_once(APPROOT.'application/applicationextension/backoffice/AbstractApplicationObjectExtension.php');
require_once(APPROOT.'application/applicationextension/iBackupExtraFilesExtension.php');
require_once(APPROOT.'application/applicationextension/iKPILoggerExtension.php');
require_once(APPROOT.'application/applicationextension/iModuleExtension.php');

View File

@@ -0,0 +1,58 @@
<?php
/**
* Extend this class instead of iApplicationObjectExtension if you don't need to overload all methods
*
* @api
* @deprecated 3.1.0 N°4756 use the new event service instead, see {@see DBObject::FireEvent()} method
* @package ORMExtensibilityAPI
* @since 2.7.0
*/
abstract class AbstractApplicationObjectExtension implements iApplicationObjectExtension
{
/**
* @inheritDoc
*/
public function OnIsModified($oObject)
{
return false;
}
/**
* @inheritDoc
*/
public function OnCheckToWrite($oObject)
{
return array();
}
/**
* @inheritDoc
*/
public function OnCheckToDelete($oObject)
{
return array();
}
/**
* @inheritDoc
*/
public function OnDBUpdate($oObject, $oChange = null)
{
}
/**
* @inheritDoc
*/
public function OnDBInsert($oObject, $oChange = null)
{
}
/**
* @inheritDoc
*/
public function OnDBDelete($oObject, $oChange = null)
{
}
}

View File

@@ -0,0 +1,111 @@
<?php
/**
* Implement this interface to perform specific operations when objects are manipulated
*
* Note that those methods will be called when objects are manipulated, either in a programmatic way
* or through the GUI.
*
* @api
* @deprecated 3.1.0 N°4756 use the new event service instead, see {@see DBObject::FireEvent()} method. More details on each method PHPDoc.
* @package ORMExtensibilityAPI
*/
interface iApplicationObjectExtension
{
/**
* Invoked to determine whether an object has been modified in memory
*
* The GUI calls this verb to determine the message that will be displayed to the end-user.
* Anyhow, this API can be called in other contexts such as the CSV import tool.
*
* If the extension returns false, then the framework will perform the usual evaluation.
* Otherwise, the answer is definitively "yes, the object has changed".
*
* @param /cmdbAbstractObject $oObject The target object
*
* @return boolean True if something has changed for the target object
* @api
* @deprecated 3.1.0 N°4756 No alternative available, this API was unstable and is abandoned
*/
public function OnIsModified($oObject);
/**
* Invoked to determine whether an object can be written to the database
*
* The GUI calls this verb and reports any issue.
* Anyhow, this API can be called in other contexts such as the CSV import tool.
*
* @param \cmdbAbstractObject $oObject The target object
*
* @return string[] A list of errors message. An error message is made of one line and it can be displayed to the end-user.
* @api
* @deprecated 3.1.0 N°4756 Use EVENT_DB_CHECK_TO_WRITE event instead
*/
public function OnCheckToWrite($oObject);
/**
* Invoked to determine wether an object can be deleted from the database
*
* The GUI calls this verb and stops the deletion process if any issue is reported.
*
* Please not that it is not possible to cascade deletion by this mean: only stopper issues can be handled.
*
* @param \cmdbAbstractObject $oObject The target object
*
* @return string[] A list of errors message. An error message is made of one line and it can be displayed to the end-user.
* @api
* @deprecated 3.1.0 N°4756 Use EVENT_DB_CHECK_TO_DELETE event instead
*/
public function OnCheckToDelete($oObject);
/**
* Invoked when an object is updated into the database. The method is called right <b>after</b> the object has been written to the
* database.
*
* Useful methods you can call on $oObject :
*
* * {@see DBObject::ListPreviousValuesForUpdatedAttributes()} : list of changed attributes and their values before the change
* * {@see DBObject::Get()} : for a given attribute the new value that was persisted
*
* @param \cmdbAbstractObject $oObject The target object
* @param CMDBChange|null $oChange A change context. Since 2.0 it is fine to ignore it, as the framework does maintain this information
* once for all the changes made within the current page
*
* @return void
*
* @deprecated 3.1.0 N°4756 Use EVENT_DB_AFTER_WRITE event instead
* @api
* @since 2.7.0 N°2293 can access object changes by calling {@see DBObject::ListPreviousValuesForUpdatedAttributes()} on $oObject
*/
public function OnDBUpdate($oObject, $oChange = null);
/**
* Invoked when an object is created into the database
*
* The method is called right <b>after</b> the object has been written to the database.
*
* @param \cmdbAbstractObject $oObject The target object
* @param CMDBChange|null $oChange A change context. Since 2.0 it is fine to ignore it, as the framework does maintain this information
* once for all the changes made within the current page
*
* @return void
* @deprecated 3.1.0 N°4756 Use EVENT_DB_AFTER_WRITE event instead
* @api
*/
public function OnDBInsert($oObject, $oChange = null);
/**
* Invoked when an object is deleted from the database
*
* The method is called right <b>before</b> the object will be deleted from the database.
*
* @param \cmdbAbstractObject $oObject The target object
* @param CMDBChange|null $oChange A change context. Since 2.0 it is fine to ignore it, as the framework does maintain this information
* once for all the changes made within the current page
*
* @return void
* @deprecated 3.1.0 N°4756 Use EVENT_DB_AFTER_DELETE event instead
* @api
*/
public function OnDBDelete($oObject, $oChange = null);
}

View File

@@ -214,15 +214,6 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
*/
protected static bool $bBlockEventDBLinksChanged = false;
/**
* If set to true, the object is considered as modified, whatever the actual state is.
* This is used when an object is modified indirectly (eg. through a linked set)
*
* @var bool
*
* @since 3.3.0 N°8210 - Remove iApplicationObjectExtension
*/
private bool $bIsMarkedAsModified = false;
/**
* Constructor from a row of data (as a hash 'attcode' => value)
@@ -759,10 +750,10 @@ HTML
$oPage->SetCurrentTab($sTabCode, $oAttDef->GetLabel().$sCount, $sTabDescription);
$aArgs = array('this' => $this);
$sEditWhen = $oAttDef->GetEditWhen();
// Calculate if edit_when allows to edit based on current $bEditMode
$bIsEditableBasedOnEditWhen = ($sEditWhen === LINKSET_EDITWHEN_ALWAYS) ||
$bIsEditableBasedOnEditWhen = ($sEditWhen === LINKSET_EDITWHEN_ALWAYS) ||
($bEditMode ? $sEditWhen === LINKSET_EDITWHEN_ON_HOST_EDITION : $sEditWhen === LINKSET_EDITWHEN_ON_HOST_DISPLAY);
$bReadOnly = ($iFlags & (OPT_ATT_READONLY | OPT_ATT_SLAVE)) || !$bIsEditableBasedOnEditWhen;
@@ -1218,6 +1209,35 @@ HTML
return DataTableUIBlockFactory::MakeForObject($oPage, $sTableId, $oSet, $aExtraParams);
}
/**
* Get the HTML fragment corresponding to the display of a table representing a set of objects
*
* @param WebPage $oPage The page object is used for out-of-band information (mostly scripts) output
* @param \DBObjectSet $oSet The set of objects to display
* @param array $aExtraParams key used :
* <ul>
* <li>view_link : if true then for extkey will display links with friendly name and make column sortable, default true
* <li>menu : if true prints DisplayBlock menu, default true
* <li>display_aliases : list of query aliases that will be printed, defaults to [] (displays all)
* <li>zlist : name of the zlist to use, false to disable zlist lookup, default to 'list'
* <li>extra_fields : list of <alias>.<attcode> to add to the result, separator ',', defaults to empty string
* </ul>
*
* @return String The HTML fragment representing the table of objects. <b>Warning</b> : no JS added to handled
* pagination or table sorting !
*
* @see DisplayBlock to get a similar table but with the JS for pagination & sorting
*
* @deprecated 3.0.0 use GetDisplaySetBlock
*/
public static function GetDisplaySet(WebPage $oPage, DBObjectSet $oSet, $aExtraParams = array())
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use GetDisplaySetBlock');
$oPage->AddUiBlock(static::GetDisplaySetBlock($oPage, $oSet, $aExtraParams));
return "";
}
/**
* @param WebPage $oPage
* @param \DBObjectSet $oSet
@@ -1391,6 +1411,129 @@ HTML
//DataTableUIBlockFactory::MakeForStaticData('', $aHeader, $aRows);
}
/**
* @param WebPage $oPage
* @param \CMDBObjectSet $oSet
* @param array $aExtraParams key used :
* <ul>
* <li>view_link : if true then for extkey will display links with friendly name and make column sortable, default true
* <li>menu : if true prints DisplayBlock menu, default true
* <li>display_aliases : list of query aliases that will be printed, defaults to [] (displays all)
* <li>zlist : name of the zlist to use, false to disable zlist lookup, default to 'list'
* <li>extra_fields : list of <alias>.<attcode> to add to the result, separator ',', defaults to empty string
* </ul>
*
* @return string
* @throws \CoreException
* @throws \DictExceptionMissingString
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @deprecated 3.0.0
*/
public static function GetDisplayExtendedSet(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array())
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod();
if (empty($aExtraParams['currentId'])) {
$iListId = utils::GetUniqueId(); // Works only if not in an Ajax page !!
} else {
$iListId = $aExtraParams['currentId'];
}
$aList = array();
// Initialize and check the parameters
$bViewLink = isset($aExtraParams['view_link']) ? $aExtraParams['view_link'] : true;
$bDisplayMenu = isset($aExtraParams['menu']) ? $aExtraParams['menu'] == true : true;
// Check if there is a list of aliases to limit the display to...
$aDisplayAliases = isset($aExtraParams['display_aliases']) ? explode(',',
$aExtraParams['display_aliases']) : array();
$sZListName = isset($aExtraParams['zlist']) ? ($aExtraParams['zlist']) : 'list';
$aExtraFieldsRaw = isset($aExtraParams['extra_fields']) ? explode(',',
trim($aExtraParams['extra_fields'])) : array();
$aExtraFields = array();
$sAttCode = '';
foreach($aExtraFieldsRaw as $sFieldName)
{
// Ignore attributes not of the main queried class
if (preg_match('/^(.*)\.(.*)$/', $sFieldName, $aMatches))
{
$sClassAlias = $aMatches[1];
$sAttCode = $aMatches[2];
if (array_key_exists($sClassAlias, $oSet->GetSelectedClasses()))
{
$aExtraFields[$sClassAlias][] = $sAttCode;
}
}
else
{
$aExtraFields['*'] = $sAttCode;
}
}
$aClasses = $oSet->GetFilter()->GetSelectedClasses();
$aAuthorizedClasses = array();
foreach($aClasses as $sAlias => $sClassName)
{
if ((UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) != UR_ALLOWED_NO) &&
((count($aDisplayAliases) == 0) || (in_array($sAlias, $aDisplayAliases))))
{
$aAuthorizedClasses[$sAlias] = $sClassName;
}
}
foreach($aAuthorizedClasses as $sAlias => $sClassName)
{
if (array_key_exists($sAlias, $aExtraFields))
{
$aList[$sAlias] = $aExtraFields[$sAlias];
}
else
{
$aList[$sAlias] = array();
}
if ($sZListName !== false)
{
$aDefaultList = self::FlattenZList(MetaModel::GetZListItems($sClassName, $sZListName));
$aList[$sAlias] = array_merge($aDefaultList, $aList[$sAlias]);
}
// Filter the list to removed linked set since we are not able to display them here
foreach ($aList[$sAlias] as $index => $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode);
if ($oAttDef instanceof AttributeLinkedSet)
{
// Removed from the display list
unset($aList[$sAlias][$index]);
}
}
if (empty($aList[$sAlias]))
{
unset($aList[$sAlias], $aAuthorizedClasses[$sAlias]);
}
}
$sSelectMode = 'none';
$oDataTable = new DataTable($iListId, $oSet, $aAuthorizedClasses);
$oSettings = DataTableSettings::GetDataModelSettings($aAuthorizedClasses, $bViewLink, $aList);
$bDisplayLimit = isset($aExtraParams['display_limit']) ? $aExtraParams['display_limit'] : true;
if ($bDisplayLimit)
{
$iDefaultPageSize = appUserPreferences::GetPref('default_page_size',
MetaModel::GetConfig()->GetMinDisplayLimit());
$oSettings->iDefaultPageSize = $iDefaultPageSize;
}
$oSettings->aSortOrder = MetaModel::GetOrderByDefault($sClassName);
return $oDataTable->Display($oPage, $oSettings, $bDisplayMenu, $sSelectMode, $bViewLink, $aExtraParams);
}
/**
* @param WebPage $oPage
* @param \CMDBObjectSet $oSet
@@ -1579,7 +1722,7 @@ HTML
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \Exception
*
*
* @internal Only to be used by `/webservices/export.php` : this is a legacy method that produces wrong HTML (no TR on table body rows)
*/
public static function GetSetAsHTMLSpreadsheet(DBObjectSet $oSet, $aParams = array())
@@ -2080,7 +2223,7 @@ JS
);
// test query link
$sTestResId = 'query_res_'.$sFieldPrefix.$sAttCode.$sNameSuffix;
$sTestResId = 'query_res_'.$sFieldPrefix.$sAttCode.$sNameSuffix; //$oPage->GetUniqueId();
$sBaseUrl = utils::GetAbsoluteUrlAppRoot().'pages/run_query.php?expression=';
$sTestQueryLbl = Dict::S('UI:Edit:TestQuery');
$oTestQueryButton = ButtonUIBlockFactory::MakeIconAction(
@@ -2530,7 +2673,7 @@ HTML;
}
break;
}
$sPattern = addslashes($oAttDef->GetValidationPattern()); //'^([0-9]+)$';
$sPattern = addslashes($oAttDef->GetValidationPattern()); //'^([0-9]+)$';
if (!empty($aEventsList))
{
if (!is_numeric($sNullValue))
@@ -3441,13 +3584,15 @@ EOF
} else {
//we can directly apply the stimuli
$sExceptionMessage = null;
$bApplyStimulus = false;
try {
$bApplyStimulus = $this->ApplyStimulus($sStimulus); // will write the object in the DB
} catch (Exception $oException) {
$bApplyStimulus = $this->ApplyStimulus($sStimulus); // will write the object in the DB
}
catch (Exception $oException) {
// Catch any exception happening during the stimulus
$bApplyStimulus = false;
$sExceptionMessage = ($oException instanceof CoreCannotSaveObjectException) ? $oException->getHtmlMessage() : $oException->getMessage();
} finally {
}
finally {
if ($sOwnershipToken !== null) {
// Release the concurrent lock, if any
iTopOwnershipLock::ReleaseLock($sClass, $iKey, $sOwnershipToken);
@@ -3455,8 +3600,9 @@ EOF
if (!$bApplyStimulus) {
// Throw an application oriented exception if necessary
throw new ApplicationException($sExceptionMessage ?? Dict::S('UI:FailedToApplyStimuli'));
} else {
return true;
}
return true;
}
}
@@ -3696,7 +3842,7 @@ HTML;
public function GetHilightClass()
{
// Possible return values are:
// HILIGHT_CLASS_CRITICAL, HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE
// HILIGHT_CLASS_CRITICAL, HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE
$current = parent::GetHilightClass(); // Default computation
// Invoke extensions before the deletion (the deletion will do some cleanup and we might loose some information
@@ -4396,6 +4542,21 @@ HTML;
return $res;
}
protected function PostInsertActions(): void
{
parent::PostInsertActions();
// Invoke extensions after insertion (the object must exist, have an id, etc.)
/** @var \iApplicationObjectExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins(iApplicationObjectExtension::class) as $oExtensionInstance) {
$sExtensionClass = get_class($oExtensionInstance);
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnDBInsert()");
$oKPI = new ExecutionKPI();
$oExtensionInstance->OnDBInsert($this, self::GetCurrentChange());
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBInsert');
}
}
/**
* @inheritdoc
* Attaches InlineImages to the current object
@@ -4428,6 +4589,21 @@ HTML;
return $res;
}
protected function PostUpdateActions(array $aChanges): void
{
parent::PostUpdateActions($aChanges);
// Invoke extensions after the update (could be before)
/** @var \iApplicationObjectExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins(iApplicationObjectExtension::class) as $oExtensionInstance) {
$sExtensionClass = get_class($oExtensionInstance);
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnDBUpdate()");
$oKPI = new ExecutionKPI();
$oExtensionInstance->OnDBUpdate($this, self::GetCurrentChange());
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBUpdate');
}
}
/**
* @param string $sMessageIdPrefix
*
@@ -4463,6 +4639,21 @@ HTML;
return $oDeletionPlan;
}
final protected function PreDeleteActions(): void
{
/** @var \iApplicationObjectExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{
$sExtensionClass = get_class($oExtensionInstance);
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnDBDelete()");
$oKPI = new ExecutionKPI();
$oExtensionInstance->OnDBDelete($this, self::GetCurrentChange());
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBDelete');
}
parent::PreDeleteActions();
}
final protected function PostDeleteActions(): void
{
parent::PostDeleteActions();
@@ -4475,20 +4666,25 @@ HTML;
return true;
}
return $this->bIsMarkedAsModified;
}
// Plugins
//
/** @var \iApplicationObjectExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{
$sExtensionClass = get_class($oExtensionInstance);
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnIsModified()");
$oKPI = new ExecutionKPI();
$bIsModified = $oExtensionInstance->OnIsModified($this);
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnIsModified');
if ($bIsModified) {
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnIsModified() -> true");
return true;
} else {
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnIsModified() -> false");
}
}
/**
* Override the default modification state of the object.
*
* The object is considered as modified, whatever the actual state is.
* This is used when an object is modified indirectly (eg. through a linked set)
*
* @return void
*/
public function MarkObjectAsModified(): void
{
$this->bIsMarkedAsModified = true;
return false;
}
/**
@@ -4502,7 +4698,7 @@ HTML;
}
/**
* Whether to bypass the checks of user rights when writing this object
* Whether to bypass the checks of user rights when writing this object, could be used in {@link \iApplicationObjectExtension::OnCheckToWrite()}
*
* @return bool
*/
@@ -4531,6 +4727,22 @@ HTML;
{
parent::DoCheckToWrite();
// Plugins
//
/** @var \iApplicationObjectExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{
$sExtensionClass = get_class($oExtensionInstance);
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnCheckToWrite()");
$oKPI = new ExecutionKPI();
$aNewIssues = $oExtensionInstance->OnCheckToWrite($this);
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnCheckToWrite');
if (is_array($aNewIssues) && (count($aNewIssues) > 0)) // Some extensions return null instead of an empty array
{
$this->m_aCheckIssues = array_merge($this->m_aCheckIssues, $aNewIssues);
}
}
// User rights
//
if (!$this->bAllowWrite)
@@ -4567,6 +4779,22 @@ HTML;
{
parent::DoCheckToDelete($oDeletionPlan);
// Plugins
//
/** @var \iApplicationObjectExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{
$sExtensionClass = get_class($oExtensionInstance);
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnCheckToDelete()");
$oKPI = new ExecutionKPI();
$aNewIssues = $oExtensionInstance->OnCheckToDelete($this);
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnCheckToDelete');
if (is_array($aNewIssues) && count($aNewIssues) > 0)
{
$this->m_aDeleteIssues = array_merge($this->m_aDeleteIssues, $aNewIssues);
}
}
// User rights
//
if (! $this->bAllowDelete)
@@ -4646,6 +4874,66 @@ HTML;
}
}
/**
* @param $sCurrentState
* @param $sStimulus
* @param $bOnlyNewOnes
*
* @return array
* @throws \ApplicationException
* @throws \CoreException
* @deprecated Since iTop 2.4, use DBObject::GetTransitionAttributes() instead.
*/
public function GetExpectedAttributes($sCurrentState, $sStimulus, $bOnlyNewOnes)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('Since iTop 2.4, use DBObject::GetTransitionAttributes() instead');
$aTransitions = $this->EnumTransitions();
if (!isset($aTransitions[$sStimulus])) {
// Invalid stimulus
throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus,
$this->GetName(), $this->GetStateLabel()));
}
$aTransition = $aTransitions[$sStimulus];
$sTargetState = $aTransition['target_state'];
$aTargetStates = MetaModel::EnumStates(get_class($this));
$aTargetState = $aTargetStates[$sTargetState];
$aCurrentState = $aTargetStates[$this->GetState()];
$aExpectedAttributes = $aTargetState['attribute_list'];
$aCurrentAttributes = $aCurrentState['attribute_list'];
$aComputedAttributes = array();
foreach($aExpectedAttributes as $sAttCode => $iExpectCode)
{
if (!array_key_exists($sAttCode, $aCurrentAttributes))
{
$aComputedAttributes[$sAttCode] = $iExpectCode;
}
else
{
if (!($aCurrentAttributes[$sAttCode] & (OPT_ATT_HIDDEN | OPT_ATT_READONLY)))
{
$iExpectCode = $iExpectCode & ~(OPT_ATT_MUSTPROMPT | OPT_ATT_MUSTCHANGE); // Already prompted/changed, reset the flags
}
// Later: better check if the attribute is not *null*
if (($iExpectCode & OPT_ATT_MANDATORY) && ($this->Get($sAttCode) != ''))
{
$iExpectCode = $iExpectCode & ~(OPT_ATT_MANDATORY); // If the attribute is present, then no need to request its presence
}
$aComputedAttributes[$sAttCode] = $iExpectCode;
}
$aComputedAttributes[$sAttCode] = $aComputedAttributes[$sAttCode] & ~(OPT_ATT_READONLY | OPT_ATT_HIDDEN); // Don't care about this form now
if ($aComputedAttributes[$sAttCode] == 0)
{
unset($aComputedAttributes[$sAttCode]);
}
}
return $aComputedAttributes;
}
/**
* Display a form for modifying several objects at once
* The form will be submitted to the current page, with the specified additional values
@@ -5521,7 +5809,7 @@ JS
{
$this->NotifyAttachedObjectsOnLinkClassModification();
$this->RemoveObjectAwaitingEventDbLinksChanged(get_class($this), $this->GetKey());
$this->FireEvent(EVENT_DB_AFTER_WRITE, ['is_new' => $bIsNew, 'changes' => $aChanges, 'stimulus_applied' => $sStimulusBeingApplied, 'cmdb_change' => self::GetCurrentChange()]);
$this->FireEvent(EVENT_DB_AFTER_WRITE, ['is_new' => $bIsNew, 'changes' => $aChanges, 'stimulus_applied' => $sStimulusBeingApplied]);
}
//////////////
@@ -5559,7 +5847,7 @@ JS
final protected function FireEventAfterDelete(): void
{
$this->NotifyAttachedObjectsOnLinkClassModification();
$this->FireEvent(EVENT_DB_AFTER_DELETE, ['cmdb_change' => self::GetCurrentChange()]);
$this->FireEvent(EVENT_DB_AFTER_DELETE);
}
/**

View File

@@ -562,70 +562,7 @@ Call $this->AddInitialAttributeFlags($sAttCode, $iFlags) for all the initial att
</event_data>
</event>
</events>
<forms>
<form id="DashletHeaderDynamicProperties" xsi:type="FormType">
<form_types>
<form_type id="title" xsi:type="TextType">
<options>
<label>UI:DashletHeaderDynamic:Prop-Title</label>
<default>UI:DashletHeaderDynamic:Prop-Title:Default</default>
</options>
</form_type>
<form_type id="icon" xsi:type="IconType">
<options>
<label>UI:DashletHeaderDynamic:Prop-Icon</label>
<default>images/icons/icons8-customer.svg</default>
</options>
</form_type>
<form_type id="subtitle" xsi:type="TextType">
<options>
<label>UI:DashletHeaderDynamic:Prop-Subtitle</label>
<default>UI:DashletHeaderDynamic:Prop-Subtitle:Default</default>
</options>
</form_type>
<form_type id="query" xsi:type="QueryType">
<options>
<label>UI:DashletHeaderDynamic:Prop-Query</label>
<default>SELECT Contact</default>
</options>
</form_type>
<form_type id="group_by" xsi:type="GroupByAttcodeType">
<options>
<label>UI:DashletHeaderDynamic:Prop-GroupBy</label>
<default>status</default>
<class_source>query</class_source>
</options>
</form_type>
<form_type id="values" xsi:type="ValuesFromAttcodeType">
<options>
<label>UI:DashletHeaderDynamic:Prop-Values</label>
<default>
<values>
<value id="active"/>
<value id="inactive"/>
</values>
</default>
<attcode_source>group_by</attcode_source>
</options>
</form_type>
</form_types>
</form>
</forms>
<meta>
<form_type_definitions>
<form_type_definition id="IconType">
<options>
<option id="label">
<mandatory>true</mandatory>
<type>string</type>
</option>
<option id="default">
<mandatory>true</mandatory>
<type>string</type>
</option>
</options>
</form_type_definition>
</form_type_definitions>
<classes>
<class id="cmdbAbstractObject" _delta="define">
<methods>

View File

@@ -419,7 +419,7 @@ class DisplayBlock
$oSet->OptimizeColumnLoad(array($oSet->GetClassAlias() => array())); // No need to load all the columns just to get the id
while($oObject = $oSet->Fetch())
{
$aKeys[] = $oObject->GetKey();
$aKeys[] = $oObject->GetKey();
}
$oSet->Rewind();
if (count($aKeys) > 0)
@@ -772,6 +772,10 @@ class DisplayBlock
$oBlock = $this->RenderList($aExtraParams, $oPage);
break;
case 'links':
$oBlock = $this->RenderLinks($oPage, $aExtraParams);
break;
case static::ENUM_STYLE_ACTIONS:
$oBlock = $this->RenderActions($aExtraParams);
break;
@@ -791,11 +795,11 @@ class DisplayBlock
case static::ENUM_STYLE_CHART:
$oBlock = $this->RenderChart($sId, $aQueryParams, $aExtraParams);
break;
case static::ENUM_STYLE_CHART_AJAX:
$oBlock = $this->RenderChartAjax($aExtraParams);
break;
default:
// Unsupported style, do nothing.
$sHtml .= Dict::format('UI:Error:UnsupportedStyleOfBlock', $this->m_sStyle);
@@ -893,7 +897,7 @@ JS
$sClass = $this->m_oFilter->GetClass();
$bConditionAdded = false;
// If the condition is an external key with a class having a hierarchy, use a "below" criteria
if (MetaModel::IsValidAttCode($sClass, $sFilterCode))
{
@@ -902,13 +906,13 @@ JS
if ($oAttDef->IsExternalKey())
{
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($oAttDef->GetTargetClass());
if ($sHierarchicalKeyCode !== false)
{
$oFilter = new DBObjectSearch($oAttDef->GetTargetClass());
if (($sOpCode == 'IN') && is_array($condition))
{
$oFilter->AddConditionExpression(self::GetConditionIN($oFilter, 'id', $condition));
$oFilter->AddConditionExpression(self::GetConditionIN($oFilter, 'id', $condition));
}
else
{
@@ -931,21 +935,21 @@ JS
$bConditionAdded = true;
}
}
// In all other cases, just add the condition directly
if (!$bConditionAdded)
{
$this->m_oFilter->AddCondition($sFilterCode, $condition, null); // Use the default 'loose' operator
}
}
static protected function GetConditionIN($oFilter, $sFilterCode, $condition)
{
$oField = new FieldExpression($sFilterCode, $oFilter->GetClassAlias());
$sListExpr = '('.implode(', ', CMDBSource::Quote($condition)).')';
$sOQLCondition = $oField->RenderExpression()." IN $sListExpr";
$oNewCondition = Expression::FromOQL($sOQLCondition);
return $oNewCondition;
return $oNewCondition;
}
/**
@@ -1561,6 +1565,54 @@ JS
return $oContentBlock;
}
/**
* @deprecated 3.1.0 N°5957
*
* @param WebPage $oPage
* @param array $aExtraParams
*
* @return \Combodo\iTop\Application\UI\Base\Component\Html\Html|\Combodo\iTop\Application\UI\Base\Layout\UIContentBlock|string
* @throws \ApplicationException
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DictExceptionMissingString
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @throws \ReflectionException
*/
protected function RenderLinks(WebPage $oPage, array $aExtraParams)
{
// Note: No deprecation ticket yet as we want to wait and see if people / code actually use this method, in which case we might keep it.
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('This method is most likely not used throughout the application and will be removed soon. If you ever see this message, please inform us.');
$oBlock = null;
if (($this->m_oSet->CountWithLimit(1) > 0) && (UserRights::IsActionAllowed($this->m_oSet->GetClass(), UR_ACTION_READ, $this->m_oSet) == UR_ALLOWED_YES)) {
$oBlock = cmdbAbstractObject::GetDisplaySetBlock($oPage, $this->m_oSet, $aExtraParams);
} else {
$sClass = $this->m_oFilter->GetClass();
$oAttDef = MetaModel::GetAttributeDef($sClass, $this->m_aParams['target_attr']);
$sTargetClass = $oAttDef->GetTargetClass();
$oBlock = new Html('<p>'.Dict::Format('UI:NoObject_Class_ToDisplay', MetaModel::GetName($sTargetClass)).'</p>');
$bDisplayMenu = isset($this->m_aParams['menu']) ? $this->m_aParams['menu'] == true : true;
if ($bDisplayMenu) {
if ((UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES)) {
$sDefaults = '';
if (isset($this->m_aParams['default'])) {
foreach ($this->m_aParams['default'] as $sName => $sValue) {
$sDefaults .= '&'.urlencode($sName).'='.urlencode($sValue);
}
}
$oBlock->AddHtml("<p><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=modify_links&class=$sClass&sParams&link_attr=".$aExtraParams['link_attr']."&id=".$aExtraParams['object_id']."&target_class=$sTargetClass&addObjects=true$sDefaults\">".Dict::Format('UI:ClickToCreateNew',
Metamodel::GetName($sClass))."</a></p>\n");
}
}
}
return $oBlock;
}
/**
* @param string|null $sChartId
* @param array $aQueryParams

View File

@@ -358,6 +358,50 @@ class ApplicationMenu
return $aSubMenuNodes;
}
/**
* Entry point to display the whole menu into the web page, used by iTopWebPage
* @param WebPage $oPage
* @param array $aExtraParams
* @throws DictExceptionMissingString
*
* @deprecated Will be removed in 3.0.0, use static::GetMenuGroups() instead
*/
public static function DisplayMenu($oPage, $aExtraParams)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use static::GetMenuGroups() instead');
self::LoadAdditionalMenus();
// Sort the root menu based on the rank
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
$iAccordion = 0;
$iActiveAccordion = $iAccordion;
$iActiveMenu = self::GetMenuIndexById(self::GetActiveNodeId());
foreach (self::$aRootMenus as $aMenu) {
if (!self::CanDisplayMenu($aMenu)) {
continue;
}
$oMenuNode = self::GetMenuNode($aMenu['index']);
$oPage->AddToMenu('<h3 id="'.utils::GetSafeId('AccordionMenu_'.$oMenuNode->GetMenuID()).'" class="navigation-menu-group" data-menu-id="'.$oMenuNode->GetMenuId().'">'.$oMenuNode->GetTitle().'</h3>');
$oPage->AddToMenu('<div>');
$oPage->AddToMenu('<ul>');
$aChildren = self::GetChildren($aMenu['index']);
$bActive = self::DisplaySubMenu($oPage, $aChildren, $aExtraParams, $iActiveMenu);
$oPage->AddToMenu('</ul>');
if ($bActive)
{
$iActiveAccordion = $iAccordion;
}
$oPage->AddToMenu('</div>');
$iAccordion++;
}
$oPage->add_ready_script(
<<<EOF
// Accordion Menu
$("#accordion").css({display:'block'}).accordion({ header: "h3", heightStyle: "content", collapsible: true, active: $iActiveAccordion, icons: false, animate: true }); // collapsible will be enabled once the item will be selected
EOF
);
}
/**
* Recursively check if the menu and at least one of his sub-menu is enabled
* @param array $aMenu menu entry
@@ -387,6 +431,73 @@ class ApplicationMenu
return false;
}
/**
* Handles the display of the sub-menus (called recursively if necessary)
*
* @param WebPage $oPage
* @param array $aMenus
* @param array $aExtraParams
* @param int $iActiveMenu
*
* @return bool True if the currently selected menu is one of the submenus
* @throws DictExceptionMissingString
* @throws \Exception
* @deprecated Will be removed in 3.0.0, use static::GetSubMenuNodes() instead
*/
protected static function DisplaySubMenu($oPage, $aMenus, $aExtraParams, $iActiveMenu = -1)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use static::GetSubMenuNodes() instead');
// Sort the menu based on the rank
$bActive = false;
usort($aMenus, array('ApplicationMenu', 'CompareOnRank'));
foreach ($aMenus as $aMenu) {
if (!self::CanDisplayMenu($aMenu)) {
continue;
}
$index = $aMenu['index'];
$oMenu = self::GetMenuNode($index);
if ($oMenu->IsEnabled())
{
$aChildren = self::GetChildren($index);
$aCSSClasses = array('navigation-menu-item');
if (count($aChildren) > 0)
{
$aCSSClasses[] = 'submenu';
}
$sHyperlink = $oMenu->GetHyperlink($aExtraParams);
$sItemHtml = '<li id="'.utils::GetSafeId('AccordionMenu_'.$oMenu->GetMenuID()).'" class="'.implode(' ', $aCSSClasses).'" data-menu-id="'.$oMenu->GetMenuID().'">';
if ($sHyperlink != '')
{
$sLinkTarget = '';
if ($oMenu->IsHyperLinkInNewWindow())
{
$sLinkTarget .= ' target="_blank"';
}
$sURL = '"'.$oMenu->GetHyperlink($aExtraParams).'"'.$sLinkTarget;
$sTitle = utils::HtmlEntities($oMenu->GetTitle());
$sItemHtml .= "<a href={$sURL}>{$sTitle}</a>";
}
else
{
$sItemHtml .= $oMenu->GetTitle();
}
$sItemHtml .= '</li>';
$oPage->AddToMenu($sItemHtml);
if ($iActiveMenu == $index)
{
$bActive = true;
}
if (count($aChildren) > 0)
{
$oPage->AddToMenu('<ul>');
$bActive |= self::DisplaySubMenu($oPage, $aChildren, $aExtraParams, $iActiveMenu);
$oPage->AddToMenu('</ul>');
}
}
}
return $bActive;
}
/**
* Helper function to sort the menus based on their rank
* @param array $a

View File

@@ -42,7 +42,6 @@ register_shutdown_function(function()
$sReservedMemory = null;
if (!is_null($err = error_get_last()) && ($err['type'] == E_ERROR))
{
var_export($err);
// Remove stack trace from MySQLException (since 2.7.2 see N°3174)
$sMessage = $err['message'];
if (strpos($sMessage, 'MySQLException') !== false) {

View File

@@ -2424,6 +2424,19 @@ 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

View File

@@ -3,7 +3,7 @@
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
@@ -31,7 +31,7 @@ require_once(APPROOT.'/application/uiwizard.class.inc.php');
class WizardHelper
{
protected $m_aData;
public function __construct()
{
}
@@ -39,7 +39,7 @@ class WizardHelper
* Constructs the PHP target object from the parameters sent to the web page by the wizard
* @param boolean $bReadUploadedFiles True to also read any uploaded file (for blob/document fields)
* @return object
*/
*/
public function GetTargetObject($bReadUploadedFiles = false)
{
if (isset($this->m_aData['m_oCurrentValues']['id']))
@@ -207,7 +207,7 @@ class WizardHelper
else
{
$oObj->Set($sAttCode, $value);
}
}
}
}
if (isset($this->m_aData['m_sState']) && !empty($this->m_aData['m_sState']))
@@ -217,12 +217,12 @@ class WizardHelper
$oObj->DoComputeValues();
return $oObj;
}
public function GetFieldsForDefaultValue()
{
return $this->m_aData['m_aDefaultValueRequested'];
}
public function SetDefaultValue($sAttCode, $value)
{
// Protect against a request for a non existing field
@@ -247,7 +247,7 @@ class WizardHelper
$aData[] = $aRow;
}
$this->m_aData['m_oDefaultValue'][$sAttCode] = json_encode($aData);
}
else
{
@@ -256,12 +256,12 @@ class WizardHelper
}
}
}
public function GetFieldsForAllowedValues()
{
return $this->m_aData['m_aAllowedValuesRequested'];
}
public function SetAllowedValuesHtml($sAttCode, $sHtml)
{
// Protect against a request for a non existing field
@@ -270,12 +270,12 @@ class WizardHelper
$this->m_aData['m_oAllowedValues'][$sAttCode] = $sHtml;
}
}
public function ToJSON()
{
return json_encode($this->m_aData);
}
static public function FromJSON($sJSON)
{
$oWizHelper = new WizardHelper();
@@ -283,7 +283,7 @@ class WizardHelper
$oWizHelper->m_aData = $aData;
return $oWizHelper;
}
protected function GetLinkedWizardStructure($oAttDef)
{
$oWizard = new UIWizard(null, $oAttDef->GetLinkedClass());
@@ -310,7 +310,7 @@ class WizardHelper
}
return $aFields;
}
public function GetTargetClass()
{
return $this->m_aData['m_sClass'];
@@ -330,7 +330,7 @@ class WizardHelper
{
return isset($this->m_aData['m_sStimulus']) ? $this->m_aData['m_sStimulus'] : null;
}
public function GetIdForField($sFieldName)
{
$sResult = '';
@@ -375,4 +375,31 @@ JS
);
}
/*
* Function with an old pattern of code
* @deprecated 3.1.0
*/
static function ParseJsonSet($oMe, $sLinkClass, $sExtKeyToMe, $sJsonSet)
{
$aSet = json_decode($sJsonSet, true); // true means hash array instead of object
$oSet = CMDBObjectSet::FromScratch($sLinkClass);
foreach ($aSet as $aLinkObj) {
$oLink = MetaModel::NewObject($sLinkClass);
foreach ($aLinkObj as $sAttCode => $value) {
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0))
{
// For external keys: load the target object so that external fields
// get filled too
$oTargetObj = MetaModel::GetObject($oAttDef->GetTargetClass(), $value);
$oLink->Set($sAttCode, $oTargetObj);
}
$oLink->Set($sAttCode, $value);
}
$oLink->Set($sExtKeyToMe, $oMe->GetKey());
$oSet->AddObject($oLink);
}
return $oSet;
}
}

View File

@@ -15,36 +15,32 @@
"apereo/phpcas": "~1.6.0",
"firebase/php-jwt": "^6.4.0",
"guzzlehttp/guzzle": "^7.5.1",
"laminas/laminas-mail": "^2.11",
"laminas/laminas-servicemanager": "^3.5",
"league/oauth2-google": "^4.0.1",
"nikic/php-parser": "dev-master",
"nikic/php-parser": "~5.6.0",
"pear/archive_tar": "~1.4.14",
"pelago/emogrifier": "^7.2.0",
"psr/log": "^3.0.0",
"scssphp/scssphp": "^1.12.1",
"soundasleep/html2text": "~2.1",
"symfony/console": "~6.4.0",
"symfony/dotenv": "~6.4.0",
"symfony/form": "^6.4",
"symfony/framework-bundle": "~6.4.0",
"symfony/http-foundation": "~6.4.0",
"symfony/http-kernel": "~6.4.0",
"symfony/mailer": "^6.4",
"symfony/runtime": "~6.4.0",
"symfony/twig-bundle": "~6.4.0",
"symfony/var-dumper": "~6.4.0",
"symfony/yaml": "~6.4.0",
"tecnickcom/tcpdf": "^6.6.0",
"thenetworg/oauth2-azure": "^2.0"
"thenetworg/oauth2-azure": "^2.0",
"soundasleep/html2text": "~2.1"
},
"require-dev": {
"symfony/debug-bundle": "~6.4.0",
"symfony/stopwatch": "~6.4.0",
"symfony/web-profiler-bundle": "~6.4.0"
},
"repositories": [{
"type": "vcs",
"url": "https://github.com/Combodo/PHP-Parser"
}],
"suggest": {
"ext-libsodium": "Required to use the AttributeEncryptedString.",
"ext-openssl": "Can be used as a polyfill if libsodium is not installed",

2157
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,938 +0,0 @@
<?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/>
use Combodo\iTop\Application\TwigBase\Twig\TwigHelper;
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
use Combodo\iTop\Application\WebPage\WebPage;
use Combodo\iTop\Service\Notification\NotificationsRepository;
use Combodo\iTop\Service\Notification\NotificationsService;
use Combodo\iTop\Service\Router\Router;
/**
* Persistent classes (internal): user defined actions
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/core/asynctask.class.inc.php');
require_once(APPROOT.'/core/email.class.inc.php');
/**
* A user defined action, to customize the application
*
* @package iTopORM
*/
abstract class Action extends cmdbAbstractObject
{
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "name",
"complementary_name_attcode" => ['finalclass', 'description'],
"state_attcode" => "status",
"reconc_keys" => ['name'],
"db_table" => "priv_action",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"style" => new ormStyle("ibo-dm-class--Action", "ibo-dm-class-alt--Action", "var(--ibo-dm-class--Action--main-color)", "var(--ibo-dm-class--Action--complementary-color)", null, '../images/icons/icons8-in-transit.svg'),
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values" => null, "sql" => "name", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
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 AttributeEnum("status", array(
"allowed_values" => new ValueSetEnum(array('test' => 'Being tested', 'enabled' => 'In production', 'disabled' => 'Inactive')),
"styled_values" => [
'test' => new ormStyle('ibo-dm-enum--Action-status-test', 'ibo-dm-enum-alt--Action-status-test', 'var(--ibo-dm-enum--Action-status-test--main-color)', 'var(--ibo-dm-enum--Action-status-test--complementary-color)', null, null),
'enabled' => new ormStyle('ibo-dm-enum--Action-status-enabled', 'ibo-dm-enum-alt--Action-status-enabled', 'var(--ibo-dm-enum--Action-status-enabled--main-color)', 'var(--ibo-dm-enum--Action-status-enabled--complementary-color)', 'fas fa-check', null),
'disabled' => new ormStyle('ibo-dm-enum--Action-status-disabled', 'ibo-dm-enum-alt--Action-status-disabled', 'var(--ibo-dm-enum--Action-status-disabled--main-color)', 'var(--ibo-dm-enum--Action-status-disabled--complementary-color)', null, null),
],
"display_style" => 'list',
"sql" => "status",
"default_value" => "test",
"is_null_allowed" => false,
"depends_on" => array(),
)));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("trigger_list",
array("linked_class" => "lnkTriggerAction", "ext_key_to_me" => "action_id", "ext_key_to_remote" => "trigger_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => array(), "display_style" => 'property')));
MetaModel::Init_AddAttribute(new AttributeEnum("asynchronous", array("allowed_values" => new ValueSetEnum(['use_global_setting' => 'Use global settings','yes' => 'Yes' ,'no' => 'No']), "sql" => "asynchronous", "default_value" => 'use_global_setting', "is_null_allowed" => false, "depends_on" => array())));
// Display lists
// - Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list'));
// - Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'description', 'status'));
// Search criteria
// - Default criteria of the search form
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'status'));
}
/**
* Encapsulate the execution of the action and handle failure & logging
*
* @param \Trigger $oTrigger
* @param array $aContextArgs
*
* @return mixed
*/
abstract public function DoExecute($oTrigger, $aContextArgs);
/**
* @return bool
* @throws \ArchivedObjectException
* @throws \CoreException
*/
public function IsActive()
{
switch($this->Get('status'))
{
case 'enabled':
case 'test':
return true;
default:
return false;
}
}
/**
* Return true if the current action status is set on "test"
*
* @return bool
* @throws \ArchivedObjectException
* @throws \CoreException
*/
public function IsBeingTested()
{
switch($this->Get('status'))
{
case 'test':
return true;
default:
return false;
}
}
/**
* @inheritDoc
* @since 3.0.0
*/
public function AfterInsert()
{
parent::AfterInsert();
$this->DoCheckIfHasTrigger();
}
/**
* @inheritDoc
* @since 3.0.0
*/
public function AfterUpdate()
{
parent::AfterUpdate();
$this->DoCheckIfHasTrigger();
}
/**
* Check if the Action has at least 1 trigger linked. Otherwise, it adds a warning.
* @return void
* @since 3.0.0
*/
protected function DoCheckIfHasTrigger()
{
$oTriggersSet = $this->Get('trigger_list');
if ($oTriggersSet->Count() === 0) {
$this->m_aCheckWarnings[] = Dict::S('Action:WarningNoTriggerLinked');
}
}
/**
* @since 3.2.0 N°5472 method creation
*/
public function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
{
parent::DisplayBareRelations($oPage, false);
if ($oPage instanceof iTopWebPage && !$this->IsNew()) {
$this->GenerateLastExecutionsTab($oPage, $bEditMode);
}
}
/**
* @since 3.2.0 N°5472 method creation
*/
protected function GenerateLastExecutionsTab(iTopWebPage $oPage, $bEditMode)
{
$oRouter = Router::GetInstance();
$sActionLastExecutionsPageUrl = $oRouter->GenerateUrl('notifications.action.last_executions_tab', ['action_id' => $this->GetKey()]);
$oPage->AddAjaxTab('action_errors', $sActionLastExecutionsPageUrl, false, Dict::S('Action:last_executions_tab'));
}
/**
* @param \Combodo\iTop\Application\WebPage\WebPage $oPage
*
* @throws \ApplicationException
* @throws \ArchivedObjectException
* @throws \ConfigException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DictExceptionMissingString
* @throws \InvalidConfigParamException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @throws \ReflectionException
* @since 3.2.0 N°5472 method creation
*/
public function GetLastExecutionsTabContent(WebPage $oPage): void
{
$oConfig = utils::GetConfig();
$sLastExecutionDaysConfigParamName = 'notifications.last_executions_days';
$iLastExecutionDays = $oConfig->Get($sLastExecutionDaysConfigParamName);
if ($iLastExecutionDays < 0) {
throw new InvalidConfigParamException("Invalid value for {$sLastExecutionDaysConfigParamName} config parameter. Param desc: " . $oConfig->GetDescription($sLastExecutionDaysConfigParamName));
}
$sActionQueryOql = 'SELECT EventNotification WHERE action_id = :action_id';
$aActionQueryParams = ['action_id' => $this->GetKey()];
if ($iLastExecutionDays > 0) {
$sActionQueryOql .= ' AND date > DATE_SUB(NOW(), INTERVAL :days DAY)';
$aActionQueryParams['days'] = $iLastExecutionDays;
$sActionQueryLimit = Dict::Format('Action:last_executions_tab_limit_days', $iLastExecutionDays);
} else {
$sActionQueryLimit = Dict::S('Action:last_executions_tab_limit_none');
}
$oActionFilter = DBObjectSearch::FromOQL($sActionQueryOql, $aActionQueryParams);
$oSet = new DBObjectSet($oActionFilter, ['date' => false]);
$sPanelTitle = Dict::Format('Action:last_executions_tab_panel_title', $sActionQueryLimit);
$oExecutionsListBlock = DataTableUIBlockFactory::MakeForResult($oPage, 'action_executions_list', $oSet, ['panel_title' => $sPanelTitle]);
$oPage->AddUiBlock($oExecutionsListBlock);
}
/**
* Will be overloaded by the children classes to return the value of their global asynchronous setting (eg. `email_asynchronous` for `\ActionEmail`, `prefer_asynchronous` for `\ActionWebhook`, ...)
*
* @return bool true if the global setting for this kind of action if to be executed asynchronously, false otherwise.
* @since 3.2.0
*/
public static function GetAsynchronousGlobalSetting(): bool
{
return false;
}
/**
* @return bool true if that action instance should be executed asynchronously, otherwise false
* @throws \ArchivedObjectException
* @throws \CoreException
* @since 3.2.0
*/
public function IsAsynchronous(): bool
{
$sAsynchronous = $this->Get('asynchronous');
if ($sAsynchronous === 'use_global_setting') {
return static::GetAsynchronousGlobalSetting();
}
return $sAsynchronous === 'yes';
}
}
/**
* A notification
*
* @package iTopORM
*/
abstract class ActionNotification extends Action
{
/**
* @inheritDoc
* @throws \CoreException
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "name",
"complementary_name_attcode" => ['finalclass', 'description'],
"state_attcode" => "",
"reconc_keys" => ['name'],
"db_table" => "priv_action_notification",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
// Display lists
// - Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'trigger_list'));
// - Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', array('finalclass', 'description', 'status'));
MetaModel::Init_AddAttribute(new AttributeApplicationLanguage("language", array("sql"=>"language", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Search criteria
// - Criteria of the std search form
// MetaModel::Init_SetZListItems('standard_search', array('name'));
// - Default criteria of the search form
// MetaModel::Init_SetZListItems('default_search', array('name'));
}
/**
* @param $sLanguage
* @param $sLanguageCode
*
* @return array [$sPreviousLanguage, $aPreviousPluginProperties]
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \DictExceptionUnknownLanguage
* @since 3.2.0
*/
public function SetNotificationLanguage($sLanguage = null, $sLanguageCode = null){
$sPreviousLanguage = Dict::GetUserLanguage();
$aPreviousPluginProperties = ApplicationContext::GetPluginProperties('QueryLocalizerPlugin');
$sLanguage = $sLanguage ?? $this->Get('language');
$sLanguageCode = $sLanguageCode ?? $sLanguage;
if (!utils::IsNullOrEmptyString($sLanguage)) {
// If a language is specified for this action, force this language
// when rendering all placeholders inside this message
Dict::SetUserLanguage($sLanguage);
AttributeDateTime::LoadFormatFromConfig();
ApplicationContext::SetPluginProperty('QueryLocalizerPlugin', 'language_code', $sLanguageCode);
}
return [$sPreviousLanguage, $aPreviousPluginProperties];
}
}
/**
* An email notification
*
* @package iTopORM
*/
class ActionEmail extends ActionNotification
{
/**
* @var string
* @since 3.0.1
*/
const ENUM_HEADER_NAME_MESSAGE_ID = 'Message-ID';
/**
* @var string
* @since 3.0.1
*/
const ENUM_HEADER_NAME_REFERENCES = 'References';
/**
* @var string
* @since 3.1.0
*/
const TEMPLATE_BODY_CONTENT = '$content$';
/**
* Wraps the 'body' of the message for previewing inside an IFRAME -- i.e. without any of the iTop stylesheets being applied
* @var string
* @since 3.1.0
*/
const CONTENT_HIGHLIGHT = '<div style="border:2px dashed #6800ff;position:relative;padding:2px;margin-top:14px;"><div style="background-color:#6800ff;color:#fff;font-family:Courier New, sans-serif;font-size:14px;line-height:16px;padding:3px;display:block;position:absolute;top:-22px;right:0;">$content$</div>%s</div>';
/**
* Wraps a placeholder of the email's body for previewing inside an IFRAME -- i.e. without any of the iTop stylesheets being applied
* @var string
*/
const FIELD_HIGHLIGHT = '<span style="background-color:#6800ff;color:#fff;font-size:smaller;font-family:Courier New, sans-serif;padding:2px;">\\$$1\\$</span>';
/**
* @inheritDoc
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array('name'),
"db_table" => "priv_action_email",
"db_key_field" => "id",
"db_finalclass_field" => "",
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-mailing.svg'),
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeEmailAddress("test_recipient", array("allowed_values" => null, "sql" => "test_recipient", "default_value" => "", "is_null_allowed" => true, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeString("from", array("allowed_values" => null, "sql" => "from", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeString("from_label", array("allowed_values" => null, "sql" => "from_label", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeString("reply_to", array("allowed_values" => null, "sql" => "reply_to", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeString("reply_to_label", array("allowed_values" => null, "sql" => "reply_to_label", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeOQL("to", array("allowed_values" => null, "sql" => "to", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeOQL("cc", array("allowed_values" => null, "sql" => "cc", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeOQL("bcc", array("allowed_values" => null, "sql" => "bcc", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeTemplateString("subject", array("allowed_values" => null, "sql" => "subject", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeTemplateHTML("body", array("allowed_values" => null, "sql" => "body", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeEnum("importance", array("allowed_values" => new ValueSetEnum('low,normal,high'), "sql" => "importance", "default_value" => 'normal', "is_null_allowed" => false, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeBlob("html_template", array("is_null_allowed"=>true, "depends_on"=>array(), "always_load_in_tables"=>false)));
MetaModel::Init_AddAttribute(new AttributeEnum("ignore_notify", array("allowed_values" => new ValueSetEnum('yes,no'), "sql" => "ignore_notify", "default_value" => 'yes', "is_null_allowed" => false, "depends_on" => array())));
// Display lists
// - Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array(
'col:col1' => array(
'fieldset:ActionEmail:main' => array(
0 => 'name',
1 => 'description',
2 => 'status',
3 => 'language',
4 => 'html_template',
5 => 'subject',
6 => 'body',
// 5 => 'importance', not handled when sending the mail, better hide it then
),
'fieldset:ActionEmail:trigger' => array(
0 => 'trigger_list',
1 => 'asynchronous'
),
),
'col:col2' => array(
'fieldset:ActionEmail:recipients' => array(
0 => 'from',
1 => 'from_label',
2 => 'reply_to',
3 => 'reply_to_label',
4 => 'test_recipient',
5 => 'ignore_notify',
6 => 'to',
7 => 'cc',
8 => 'bcc',
),
),
));
// - Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', array('status', 'to', 'subject', 'language'));
// Search criteria
// - Standard criteria of the search
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'status', 'subject', 'language'));
// - Default criteria for the search
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'status', 'subject', 'language'));
}
// count the recipients found
protected $m_iRecipients;
// Errors management : not that simple because we need that function to be
// executed in the background, while making sure that any issue would be reported clearly
protected $m_aMailErrors; //array of strings explaining the issue
/**
* Return the list of emails as a string, or a detailed error description
*
* @param string $sRecipAttCode
* @param array $aArgs
*
* @return string
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
protected function FindRecipients($sRecipAttCode, $aArgs)
{
$oTrigger = $aArgs['trigger->object()'] ?? null;
$sOQL = $this->Get($sRecipAttCode);
if (utils::IsNullOrEmptyString($sOQL)) return '';
try
{
$oSearch = DBObjectSearch::FromOQL($sOQL);
if ($this->Get('ignore_notify') === 'no') {
// In theory, it is possible to notify *any* kind of object,
// as long as there is an email attribute in the class
// So let's not assume that the selected class is a Person
$sFirstSelectedClass = $oSearch->GetClass();
if (MetaModel::IsValidAttCode($sFirstSelectedClass, 'notify')) {
$oSearch->AddCondition('notify', 'yes');
}
}
$oSearch->AllowAllData();
}
catch (OQLException $e)
{
$this->m_aMailErrors[] = "query syntax error for recipient '$sRecipAttCode'";
return $e->getMessage();
}
$sClass = $oSearch->GetClass();
// Determine the email attribute (the first one will be our choice)
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{
if ($oAttDef instanceof AttributeEmailAddress)
{
$sEmailAttCode = $sAttCode;
// we've got one, exit the loop
break;
}
}
if (!isset($sEmailAttCode))
{
$this->m_aMailErrors[] = "wrong target for recipient '$sRecipAttCode'";
return "The objects of the class '$sClass' do not have any email attribute";
}
if($oTrigger !== null && in_array('Contact', MetaModel::EnumParentClasses($sClass, ENUM_CHILD_CLASSES_ALL), true)) {
$aArgs['trigger_id'] = $oTrigger->GetKey();
$aArgs['action_id'] = $this->GetKey();
$sSubscribedContactsOQL = NotificationsRepository::GetInstance()->GetSearchOQLContactUnsubscribedByTriggerAndAction();
$sSubscribedContactsOQL->ApplyParameters($aArgs);
$sAlias = $oSearch->GetClassAlias();
$oSearch->AddConditionExpression(Expression::FromOQL("`$sAlias`.id NOT IN ($sSubscribedContactsOQL)"));
}
$oSet = new DBObjectSet($oSearch, array() /* order */, $aArgs);
$aRecipients = array();
while ($oObj = $oSet->Fetch())
{
$sAddress = trim($oObj->Get($sEmailAttCode));
if (utils::IsNotNullOrEmptyString($sAddress))
{
$aRecipients[] = $sAddress;
$this->m_iRecipients++;
}
if ($oTrigger !== null && in_array('Contact', MetaModel::EnumParentClasses($sClass, ENUM_CHILD_CLASSES_ALL), true)) {
NotificationsService::GetInstance()->RegisterSubscription($oTrigger, $this, $oObj);
}
}
return implode(', ', $aRecipients);
}
/**
* @inheritDoc
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
*/
public function DoExecute($oTrigger, $aContextArgs)
{
if (MetaModel::IsLogEnabledNotification())
{
$oLog = new EventNotificationEmail();
if ($this->IsBeingTested())
{
$oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
}
else
{
$oLog->Set('message', 'Notification pending');
}
$oLog->Set('userinfo', UserRights::GetUser());
$oLog->Set('trigger_id', $oTrigger->GetKey());
$oLog->Set('action_id', $this->GetKey());
$oLog->Set('object_id', $aContextArgs['this->object()']->GetKey());
$oLog->Set('object_class', get_class($aContextArgs['this->object()']));
// Must be inserted now so that it gets a valid id that will make the link
// between an eventual asynchronous task (queued) and the log
$oLog->DBInsertNoReload();
}
else
{
$oLog = null;
}
try
{
$sRes = $this->_DoExecute($oTrigger, $aContextArgs, $oLog);
if ($this->IsBeingTested())
{
$sPrefix = 'TEST ('.$this->Get('test_recipient').') - ';
}
else
{
$sPrefix = '';
}
if ($oLog)
{
$oLog->Set('message', $sPrefix . $sRes);
$oLog->DBUpdate();
}
}
catch (Exception $e)
{
if ($oLog)
{
$oLog->Set('message', 'Error: '.$e->getMessage());
try
{
$oLog->DBUpdate();
}
catch (Exception $eSecondTryUpdate)
{
IssueLog::Error("Failed to process email ".$oLog->GetKey()." - reason: ".$e->getMessage()."\nTrace:\n".$e->getTraceAsString());
$oLog->Set('message', 'Error: more details in the log for email "'.$oLog->GetKey().'"');
$oLog->DBUpdate();
}
}
}
}
/**
* @param \Trigger $oTrigger
* @param array $aContextArgs
* @param \EventNotification $oLog
*
* @return string
* @throws \CoreException
* @throws \Exception
*/
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
{
$sStyles = file_get_contents(APPROOT . utils::GetCSSFromSASS("css/email.scss"));
$sStyles .= MetaModel::GetConfig()->Get('email_css');
$oEmail = new EMail();
$aEmailContent = $this->PrepareMessageContent($aContextArgs, $oLog);
$oEmail->SetSubject($aEmailContent['subject']);
$oEmail->SetBody($aEmailContent['body'], 'text/html', $sStyles);
$oEmail->SetRecipientTO($aEmailContent['to']);
$oEmail->SetRecipientCC($aEmailContent['cc']);
$oEmail->SetRecipientBCC($aEmailContent['bcc']);
$oEmail->SetRecipientFrom($aEmailContent['from'], $aEmailContent['from_label']);
$oEmail->SetRecipientReplyTo($aEmailContent['reply_to'], $aEmailContent['reply_to_label']);
$oEmail->SetReferences($aEmailContent['references']);
$oEmail->SetMessageId($aEmailContent['message_id']);
$oEmail->SetInReplyTo($aEmailContent['in_reply_to']);
foreach($aEmailContent['attachments'] as $aAttachment) {
$oEmail->AddAttachment($aAttachment['data'], $aAttachment['filename'], $aAttachment['mime_type']);
}
if (empty($this->m_aMailErrors))
{
if ($this->m_iRecipients == 0)
{
return 'No recipient';
}
else
{
$aErrors = [];
$iRes = $oEmail->Send($aErrors, $this->IsAsynchronous() ? Email::ENUM_SEND_FORCE_ASYNCHRONOUS : Email::ENUM_SEND_FORCE_SYNCHRONOUS, $oLog);
switch ($iRes)
{
case EMAIL_SEND_OK:
return "Sent";
case EMAIL_SEND_PENDING:
return "Pending";
case EMAIL_SEND_ERROR:
return "Errors: ".implode(', ', $aErrors);
}
}
} else {
if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0) {
$sError = implode(', ', $this->m_aMailErrors);
} else {
$sError = 'Unknown reason';
}
return 'Notification was not sent: '.$sError;
}
}
/**
* @param array $aContextArgs
* @param \EventNotification $oLog
*
* @return array
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \DictExceptionMissingString
* @throws \DictExceptionUnknownLanguage
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @since 3.1.0 N°918
*/
protected function PrepareMessageContent($aContextArgs, &$oLog): array
{
$aMessageContent = [
'to' => '',
'cc' => '',
'bcc' => '',
'from' => '',
'from_label' => '',
'reply_to' => '',
'reply_to_label' => '',
'subject' => '',
'body' => '',
'references' => '',
'message_id' => '',
'in_reply_to' => '',
'attachments' => [],
];
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
[$sPreviousLanguage, $aPreviousPluginProperties] = $this->SetNotificationLanguage();
try
{
$this->m_iRecipients = 0;
$this->m_aMailErrors = array();
// Determine recipients
//
$aMessageContent['to'] = $this->FindRecipients('to', $aContextArgs);
$aMessageContent['cc'] = $this->FindRecipients('cc', $aContextArgs);
$aMessageContent['bcc'] = $this->FindRecipients('bcc', $aContextArgs);
$aMessageContent['from'] = MetaModel::ApplyParams($this->Get('from'), $aContextArgs);
$aMessageContent['from_label'] = MetaModel::ApplyParams($this->Get('from_label'), $aContextArgs);
$aMessageContent['reply_to'] = MetaModel::ApplyParams($this->Get('reply_to'), $aContextArgs);
$aMessageContent['reply_to_label'] = MetaModel::ApplyParams($this->Get('reply_to_label'), $aContextArgs);
$aMessageContent['subject'] = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
$sBody = $this->BuildMessageBody(false);
$aMessageContent['body'] = MetaModel::ApplyParams($sBody, $aContextArgs);
$oObj = $aContextArgs['this->object()'];
$aMessageContent['message_id'] = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_MESSAGE_ID);
$aMessageContent['references'] = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_REFERENCES);
}
catch (Exception $e) {
/** @noinspection PhpUnhandledExceptionInspection */
throw $e;
}
finally {
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
$this->SetNotificationLanguage($sPreviousLanguage, $aPreviousPluginProperties['language_code'] ?? null);
}
if (!is_null($oLog)) {
// Note: we have to secure this because those values are calculated
// inside the try statement, and we would like to keep track of as
// many data as we could while some variables may still be undefined
if (isset($aMessageContent['to'])) {
$oLog->Set('to', $aMessageContent['to']);
}
if (isset($aMessageContent['cc'])) {
$oLog->Set('cc', $aMessageContent['cc']);
}
if (isset($aMessageContent['bcc'])) {
$oLog->Set('bcc', $aMessageContent['bcc']);
}
if (isset($aMessageContent['from'])) {
$oLog->Set('from', $aMessageContent['from']);
}
if (isset($aMessageContent['subject'])) {
$oLog->Set('subject', $aMessageContent['subject']);
}
if (isset($aMessageContent['body'])) {
$oLog->Set('body', HTMLSanitizer::Sanitize($aMessageContent['body']));
}
}
if ($this->IsBeingTested()) {
$sTestBody = $aMessageContent['body'];
$sTestBody .= "<div style=\"border: dashed;\">\n";
$sTestBody .= "<h1>Testing email notification ".$this->GetHyperlink()."</h1>\n";
$sTestBody .= "<p>The email should be sent with the following properties\n";
$sTestBody .= "<ul>\n";
$sTestBody .= "<li>TO: {$aMessageContent['to']}</li>\n";
$sTestBody .= "<li>CC: {$aMessageContent['cc']}</li>\n";
$sTestBody .= "<li>BCC: {$aMessageContent['bcc']}</li>\n";
$sTestBody .= empty($aMessageContent['from_label']) ? "<li>From: {$aMessageContent['from']}</li>\n" : "<li>From: {$aMessageContent['from_label']} &lt;{$aMessageContent['from']}&gt;</li>\n";
$sTestBody .= empty($aMessageContent['reply_to_label']) ? "<li>Reply-To: {$aMessageContent['reply_to']}</li>\n" : "<li>Reply-To: {$aMessageContent['reply_to_label']} &lt;{$aMessageContent['reply_to']}&gt;</li>\n";
$sTestBody .= "<li>References: {$aMessageContent['references']}</li>\n";
$sTestBody .= "</ul>\n";
$sTestBody .= "</p>\n";
$sTestBody .= "</div>\n";
$aMessageContent['subject'] = 'TEST['.$aMessageContent['subject'].']';
$aMessageContent['body'] = $sTestBody;
$aMessageContent['to'] = $this->Get('test_recipient');
// N°6677 Ensure emails in test are never sent to cc'd and bcc'd addresses
$aMessageContent['cc'] = '';
$aMessageContent['bcc'] = '';
}
// Note: N°4849 We pass the "References" identifier instead of the "Message-ID" on purpose as we want notifications emails to group around the triggering iTop object, not just the users' replies to the notification
$aMessageContent['in_reply_to'] = $aMessageContent['references'];
if (isset($aContextArgs['attachments']))
{
$aAttachmentReport = array();
/** @var \ormDocument $oDocument */
foreach($aContextArgs['attachments'] as $oDocument)
{
$aMessageContent['attachments'][] = ['data' => $oDocument->GetData(), 'filename' => $oDocument->GetFileName(), 'mime_type' => $oDocument->GetMimeType()];
$aAttachmentReport[] = array($oDocument->GetFileName(), $oDocument->GetMimeType(), strlen($oDocument->GetData() ?? ''));
}
$oLog->Set('attachments', $aAttachmentReport);
}
return $aMessageContent;
}
/**
* @param \DBObject $oObject
* @param string $sHeaderName {@see \ActionEmail::ENUM_HEADER_NAME_REFERENCES}, {@see \ActionEmail::ENUM_HEADER_NAME_MESSAGE_ID}
*
* @return string The formatted identifier for $sHeaderName based on $oObject
* @throws \Exception
* @since 3.1.0 N°4849
*/
protected function GenerateIdentifierForHeaders(DBObject $oObject, string $sHeaderName): string
{
$sObjClass = get_class($oObject);
$sObjId = $oObject->GetKey();
$sAppName = utils::Sanitize(ITOP_APPLICATION_SHORT, '', utils::ENUM_SANITIZATION_FILTER_VARIABLE_NAME);
switch ($sHeaderName) {
case static::ENUM_HEADER_NAME_MESSAGE_ID:
case static::ENUM_HEADER_NAME_REFERENCES:
// Prefix
$sPrefix = sprintf('%s_%s_%d', $sAppName, $sObjClass, $sObjId);
if ($sHeaderName === static::ENUM_HEADER_NAME_MESSAGE_ID) {
$sPrefix .= sprintf('_%F', microtime(true /* get as float*/));
}
// Suffix
$sSuffix = sprintf('@%s.openitop.org', MetaModel::GetEnvironmentId());
// Identifier
$sIdentifier = $sPrefix.$sSuffix;
if ($sHeaderName === static::ENUM_HEADER_NAME_REFERENCES) {
$sIdentifier = "<$sIdentifier>";
}
return $sIdentifier;
}
// Requested header name invalid
$sErrorMessage = sprintf('%s: Could not generate identifier for header "%s", only %s are supported', static::class, $sHeaderName, implode(' / ', [static::ENUM_HEADER_NAME_MESSAGE_ID, static::ENUM_HEADER_NAME_REFERENCES]));
IssueLog::Error($sErrorMessage, LogChannels::NOTIFICATIONS, [
'Object' => $sObjClass.'::'.$sObjId.' ('.$oObject->GetRawName().')',
'Action' => get_class($this).'::'.$this->GetKey().' ('.$this->GetRawName().')',
]);
throw new Exception($sErrorMessage);
}
/**
* Compose the body of the message from the 'body' attribute and the HTML template (if any)
* @since 3.1.0 N°4849
* @param bool $bHighlightPlaceholders If true add some extra HTML around placeholders to highlight them
* @return string
*/
protected function BuildMessageBody(bool $bHighlightPlaceholders = false): string
{
// Wrap content with a specific class in order to apply styles of HTML fields through the emogrifier (see `css/email.scss`)
$sBody = <<<HTML
<div class="email-is-html-content">
{$this->Get('body')}
</div>
HTML;
/** @var ormDocument $oHtmlTemplate */
$oHtmlTemplate = $this->Get('html_template');
if ($oHtmlTemplate && !$oHtmlTemplate->IsEmpty()) {
$sHtmlTemplate = $oHtmlTemplate->GetData();
if (false !== mb_strpos($sHtmlTemplate, static::TEMPLATE_BODY_CONTENT)) {
if ($bHighlightPlaceholders) {
// Highlight the $content$ block
$sBody = sprintf(static::CONTENT_HIGHLIGHT, $sBody);
}
$sBody = str_replace(static::TEMPLATE_BODY_CONTENT, $sBody, $oHtmlTemplate->GetData()); // str_replace is ok as long as both strings are well-formed UTF-8
} else {
$sBody = $oHtmlTemplate->GetData();
}
}
if($bHighlightPlaceholders) {
// Highlight all placeholders
$sBody = preg_replace('/\\$([^$]+)\\$/', static::FIELD_HIGHLIGHT, $sBody);
}
return $sBody;
}
/**
* @since 3.1.0 N°4849
* @inheritDoc
* @see cmdbAbstractObject::DisplayBareRelations()
*/
public function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
{
parent::DisplayBareRelations($oPage, false);
if (!$bEditMode) {
$oPage->SetCurrentTab('action_email__preview', Dict::S('ActionEmail:preview_tab'), Dict::S('ActionEmail:preview_tab+'));
$sBody = $this->BuildMessageBody(true);
TwigHelper::RenderIntoPage($oPage, APPROOT.'/', 'templates/datamodel/ActionEmail/email-notification-preview', ['iframe_content' => $sBody]);
}
}
/**
* @since 3.1.0
* @inheritDoc
* @see cmdbAbstractObject::DoCheckToWrite()
*/
public function DoCheckToWrite()
{
parent::DoCheckToWrite();
$oHtmlTemplate = $this->Get('html_template');
if ($oHtmlTemplate && !$oHtmlTemplate->IsEmpty()) {
if (false === mb_strpos($oHtmlTemplate->GetData(), static::TEMPLATE_BODY_CONTENT)) {
$this->m_aCheckWarnings[] = Dict::Format('ActionEmail:content_placeholder_missing', static::TEMPLATE_BODY_CONTENT, Dict::S('Class:ActionEmail/Attribute:body'));
}
}
}
/**
* @inheritDoc
* @since 3.2.0
*/
public static function GetAsynchronousGlobalSetting(): bool
{
return utils::GetConfig()->Get('email_asynchronous');
}
}

View File

@@ -1,544 +0,0 @@
<?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/>
use Combodo\iTop\Service\Notification\Event\EventNotificationNewsroomService;
/**
* Persistent classes (internal): user defined actions
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
class ExecAsyncTask implements iBackgroundProcess
{
public function GetPeriodicity()
{
return 2; // seconds
}
public function Process($iTimeLimit)
{
$sNow = date(AttributeDateTime::GetSQLFormat());
// Criteria: planned, and expected to occur... ASAP or in the past
$sOQL = "SELECT AsyncTask WHERE (status = 'planned') AND (ISNULL(planned) OR (planned < '$sNow'))";
$iProcessed = 0;
while (time() < $iTimeLimit)
{
// Next one ?
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('created' => true) /* order by*/, array(), null, 1 /* limit count */);
$oTask = $oSet->Fetch();
if (is_null($oTask))
{
// Nothing to be done
break;
}
$iProcessed++;
if ($oTask->Process())
{
$oTask->DBDelete();
}
}
return "processed $iProcessed tasks";
}
}
/**
* A
*
* @package iTopORM
*/
abstract class AsyncTask extends DBObject
{
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => array('created'),
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_async_task",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
);
MetaModel::Init_Params($aParams);
// Null is allowed to ease the migration from iTop 2.0.2 and earlier, when the status did not exist, and because the default value is not taken into account in the SQL definition
// 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"=>"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())));
MetaModel::Init_AddAttribute(new AttributeInteger("remaining_retries", array("allowed_values"=>null, "sql"=>"remaining_retries", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("last_error_code", array("allowed_values"=>null, "sql"=>"last_error_code", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("last_error", array("allowed_values"=>null, "sql"=>"last_error", "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("last_attempt", array("allowed_values"=>null, "sql"=>"last_attempt", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
}
/**
* Every is fine
*/
const OK = 0;
/**
* The task no longer exists
*/
const DELETED = 1;
/**
* The task is already being executed
*/
const ALREADY_RUNNING = 2;
/**
* The current process requests the ownership on the task.
* In case the task can be accessed concurrently, this function can be overloaded to add a critical section.
* The function must not block the caller if another process is already owning the task
*
* @return integer A code among OK/DELETED/ALREADY_RUNNING.
*/
public function MarkAsRunning()
{
try
{
if ($this->Get('status') == 'running')
{
return self::ALREADY_RUNNING;
}
else
{
$this->Set('status', 'running');
$this->Set('started', time());
$this->DBUpdate();
return self::OK;
}
}
catch(Exception $e)
{
// Corrupted task !! (for example: "Failed to reload object")
IssueLog::Error('Failed to process async task #'.$this->GetKey().' - reason: '.$e->getMessage().' - fatal error, deleting the task.');
if ($this->Get('event_id') != 0)
{
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
$oEventLog->Set('message', 'Failed, corrupted data: '.$e->getMessage());
$oEventLog->DBUpdate();
}
$this->DBDelete();
return self::DELETED;
}
}
public function GetRetryDelay($iErrorCode = null)
{
$iRetryDelay = 600;
$aRetries = MetaModel::GetConfig()->Get('async_task_retries');
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries))
{
$aConfig = $aRetries[get_class($this)];
$iRetryDelay = $aConfig['retry_delay'] ?? $iRetryDelay;
}
return $iRetryDelay;
}
public function GetMaxRetries($iErrorCode = null)
{
$iMaxRetries = 0;
$aRetries = MetaModel::GetConfig()->Get('async_task_retries');
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries))
{
$aConfig = $aRetries[get_class($this)];
$iMaxRetries = $aConfig['max_retries'] ?? $iMaxRetries;
}
return $iMaxRetries;
}
public function IsRetryDelayExponential()
{
$bExponential = false;
$aRetries = MetaModel::GetConfig()->Get('async_task_retries');
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries))
{
$aConfig = $aRetries[get_class($this)];
$bExponential = (bool) ($aConfig['exponential_delay'] ?? $bExponential);
}
return $bExponential;
}
public static function CheckRetryConfig(Config $oConfig, $sAsyncTaskClass)
{
$aMessages = [];
$aRetries = $oConfig->Get('async_task_retries');
if (is_array($aRetries) && array_key_exists($sAsyncTaskClass, $aRetries))
{
$aValidKeys = array("retry_delay", "max_retries", "exponential_delay");
$aConfig = $aRetries[$sAsyncTaskClass];
if (!is_array($aConfig))
{
$aMessages[] = Dict::Format('Class:AsyncTask:InvalidConfig_Class_Keys', $sAsyncTaskClass, implode(', ', $aValidKeys));
}
else
{
foreach($aConfig as $key => $value)
{
if (!in_array($key, $aValidKeys))
{
$aMessages[] = Dict::Format('Class:AsyncTask:InvalidConfig_Class_InvalidKey_Keys', $sAsyncTaskClass, $key, implode(', ', $aValidKeys));
}
}
}
}
return $aMessages;
}
/**
* Compute the delay to wait for the "next retry", based on the given parameters
* @param bool $bIsExponential
* @param int $iRetryDelay
* @param int $iMaxRetries
* @param int $iRemainingRetries
* @return int
*/
public static function GetNextRetryDelay($bIsExponential, $iRetryDelay, $iMaxRetries, $iRemainingRetries)
{
if ($bIsExponential)
{
$iExponent = $iMaxRetries - $iRemainingRetries;
if ($iExponent < 0) $iExponent = 0; // Safety net in case on configuration change in the middle of retries
return $iRetryDelay * (2 ** $iExponent);
}
else
{
return $iRetryDelay;
}
}
/**
* Override to notify people that a task cannot be performed
*/
protected function OnDefinitiveFailure()
{
}
protected function OnInsert()
{
$this->Set('created', time());
}
/**
* @return boolean True if the task record can be deleted
*/
public function Process()
{
// By default: consider that the task is not completed
$bRet = false;
// Attempt to take the ownership
$iStatus = $this->MarkAsRunning();
if ($iStatus == self::OK)
{
try
{
$sStatus = $this->DoProcess();
if ($this->Get('event_id') != 0)
{
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
$oEventLog->Set('message', $sStatus);
$oEventLog->DBUpdate();
}
$bRet = true;
} catch (Exception $e)
{
$this->HandleError($e->getMessage(), $e->getCode());
}
}
else
{
// Already done or being handled by another process... skip...
$bRet = false;
}
return $bRet;
}
/**
* Overridable to extend the behavior in case of error (logging)
*/
protected function HandleError($sErrorMessage, $iErrorCode)
{
if ($this->Get('last_attempt') == '')
{
// First attempt
$this->Set('remaining_retries', $this->GetMaxRetries($iErrorCode));
}
$this->SetTrim('last_error', $sErrorMessage);
$this->Set('last_error_code', $iErrorCode); // Note: can be ZERO !!!
$this->Set('last_attempt', time());
$iRemaining = $this->Get('remaining_retries');
if ($iRemaining > 0)
{
$iRetryDelay = $this->GetRetryDelay($iErrorCode);
$iNextRetryDelay = static::GetNextRetryDelay($this->IsRetryDelayExponential(), $iRetryDelay, $this->GetMaxRetries($iErrorCode), $iRemaining);
IssueLog::Info('Failed to process async task #'.$this->GetKey().' - reason: '.$sErrorMessage.' - remaining retries: '.$iRemaining.' - next retry in '.$iNextRetryDelay.'s');
if ($this->Get('event_id') != 0)
{
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
$oEventLog->Set('message', "$sErrorMessage\nFailed to process async task. Remaining retries: $iRemaining. Next retry in {$iNextRetryDelay}s");
try
{
$oEventLog->DBUpdate();
}
catch (Exception $e)
{
$oEventLog->Set('message', "Failed to process async task. Remaining retries: $iRemaining. Next retry in {$iNextRetryDelay}s, more details in the log");
$oEventLog->DBUpdate();
}
}
$this->Set('remaining_retries', $iRemaining - 1);
$this->Set('status', 'planned');
$this->Set('started', null);
$this->Set('planned', time() + $iNextRetryDelay);
}
else
{
IssueLog::Error('Failed to process async task #'.$this->GetKey().' - reason: '.$sErrorMessage);
if ($this->Get('event_id') != 0)
{
$oEventLog = MetaModel::GetObject('Event', $this->Get('event_id'));
$oEventLog->Set('message', "$sErrorMessage\nFailed to process async task.");
try
{
$oEventLog->DBUpdate();
}
catch (Exception $e)
{
$oEventLog->Set('message', 'Failed to process async task, more details in the log');
$oEventLog->DBUpdate();
}
}
$this->Set('status', 'error');
$this->Set('started', null);
$this->Set('planned', null);
$this->OnDefinitiveFailure();
}
$this->DBUpdate();
}
/**
* Throws an exception (message and code)
*
* @return string
*/
abstract public function DoProcess();
/**
* Describes the error codes that DoProcess can return by the mean of exceptions
*/
static public function EnumErrorCodes()
{
return array();
}
}
/**
* An email notification
*
* @package iTopORM
*/
class AsyncSendEmail extends AsyncTask
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "created",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_async_send_email",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeInteger("version", array("allowed_values"=>null, "sql"=>"version", "default_value"=>Email::ORIGINAL_FORMAT, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLongText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
// MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'reply_to', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list')); // Attributes to be displayed for the complete details
// MetaModel::Init_SetZListItems('list', array('name', 'status', 'to', 'subject')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
static public function AddToQueue(EMail $oEMail, $oLog)
{
$oNew = MetaModel::NewObject(__class__);
if ($oLog)
{
$oNew->Set('event_id', $oLog->GetKey());
}
$oNew->Set('to', $oEMail->GetRecipientTO(true /* string */));
$oNew->Set('subject', $oEMail->GetSubject());
$oNew->Set('version', 2);
$sMessage = $oEMail->SerializeV2();
$oNew->Set('message', $sMessage);
$oNew->DBInsert();
}
/**
* @inheritDoc
* @throws \ArchivedObjectException
* @throws \CoreException
*/
public function DoProcess()
{
$sMessage = $this->Get('message');
$iVersion = (int) $this->Get('version');
switch($iVersion)
{
case Email::FORMAT_V2:
$oEMail = Email::UnSerializeV2($sMessage);
break;
case Email::ORIGINAL_FORMAT:
$oEMail = unserialize($sMessage);
break;
default:
return 'Unknown version of the serialization format: '.$iVersion;
}
$iRes = $oEMail->Send($aIssues, true /* force synchro !!!!! */);
switch ($iRes)
{
case EMAIL_SEND_OK:
return "Sent";
case EMAIL_SEND_PENDING:
return "Bug - the email should be sent in synchronous mode";
case EMAIL_SEND_ERROR:
if (is_array($aIssues)) {
$sMessage = "Sending eMail failed: ".implode(', ', $aIssues);
} else {
$sMessage = "Sending eMail failed.";
}
throw new Exception($sMessage);
}
return '';
}
}
/**
* An async notification to be sent to iTop users through the newsroom
* @since 3.2.0
*/
class AsyncSendNewsroom extends AsyncTask {
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "created",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_async_send_newsroom",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeText("recipients", array("allowed_values"=>null, "sql"=>"recipients", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", array("targetclass"=>"Action", "allowed_values"=>null, "sql"=>"action_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalKey("trigger_id", array("targetclass"=>"Trigger", "allowed_values"=>null, "sql"=>"trigger_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("title", array("allowed_values"=>null, "sql"=>"title", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
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 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"=>'NOW()', "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
}
/**
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \MySQLException
* @throws \OQLException
*/
public static function AddToQueue(int $iActionId, int $iTriggerId, array $aRecipients, string $sMessage, string $sTitle, string $sUrl, int $iObjectId, ?string $sObjectClass): void
{
$oNew = new static();
$oNew->Set('action_id', $iActionId);
$oNew->Set('trigger_id', $iTriggerId);
$oNew->Set('recipients', json_encode($aRecipients));
$oNew->Set('message', $sMessage);
$oNew->Set('title', $sTitle);
$oNew->Set('url', $sUrl);
$oNew->Set('object_id', $iObjectId);
$oNew->Set('object_class', $sObjectClass);
$oNew->SetCurrentDate('date');
$oNew->DBInsert();
}
/**
* @inheritDoc
*/
public function DoProcess()
{
$oAction = MetaModel::GetObject('Action', $this->Get('action_id'));
$iTriggerId = $this->Get('trigger_id');
$aRecipients = json_decode($this->Get('recipients'));
$sMessage = $this->Get('message');
$sTitle = $this->Get('title');
$sUrl = $this->Get('url');
$iObjectId = $this->Get('object_id');
$sObjectClass = $this->Get('object_class');
$sDate = $this->Get('date');
foreach ($aRecipients as $iRecipientId)
{
$oEvent = EventNotificationNewsroomService::MakeEventFromAction($oAction, $iRecipientId, $iTriggerId, $sMessage, $sTitle, $sUrl, $iObjectId, $sObjectClass, $sDate);
$oEvent->DBInsertNoReload();
}
return "Sent";
}
}

View File

@@ -4,15 +4,96 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\UI\Base\Component\FieldBadge\FieldBadgeUIBlockFactory;
use Combodo\iTop\Application\UI\Links\Set\BlockLinkSetDisplayAsProperty;
use Combodo\iTop\Application\WebPage\WebPage;
use Combodo\iTop\Form\Field\LabelField;
use Combodo\iTop\Form\Field\TextAreaField;
use Combodo\iTop\Form\Form;
use Combodo\iTop\Form\Validator\CustomRegexpValidator;
use Combodo\iTop\Renderer\BlockRenderer;
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
use Combodo\iTop\Service\Links\LinkSetModel;
require_once('MyHelpers.class.inc.php');
require_once('ormdocument.class.inc.php');
require_once('ormstopwatch.class.inc.php');
require_once('ormpassword.class.inc.php');
require_once('ormcaselog.class.inc.php');
require_once('ormlinkset.class.inc.php');
require_once('ormset.class.inc.php');
require_once('ormtagset.class.inc.php');
require_once('htmlsanitizer.class.inc.php');
require_once('customfieldshandler.class.inc.php');
require_once('ormcustomfieldsvalue.class.inc.php');
require_once('datetimeformat.class.inc.php');
require_once(APPROOT.'/sources/Core/Orm/ormDocument.php');
require_once(APPROOT.'/sources/Core/Orm/ormStopWatch.php');
require_once(APPROOT.'/sources/Core/Orm/ormPassword.php');
require_once(APPROOT.'/sources/Core/Orm/ormCaseLog.php');
require_once(APPROOT.'/sources/Core/Orm/ormLinkSet.php');
require_once(APPROOT.'/sources/Core/Orm/ormSet.php');
require_once(APPROOT.'/sources/Core/Orm/ormTagSet.php');
require_once(APPROOT.'/sources/Core/Orm/ormCustomFieldsValue.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/MissingColumnException.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/iAttributeNoGroupBy.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeDefinition.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeDashboard.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeLinkedSet.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeLinkedSetIndirect.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeDBFieldVoid.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeDBField.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeInteger.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeObjectKey.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributePercentage.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeDecimal.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeBoolean.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeString.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeClass.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeClassState.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeApplicationLanguage.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeFinalClass.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributePassword.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeEncryptedString.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeText.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeLongText.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeCaseLog.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeHTML.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeEmailAddress.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeIPAddress.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributePhoneNumber.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeOQL.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeTemplateString.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeTemplateText.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeTemplateHTML.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeEnum.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeMetaEnum.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeDateTime.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeDuration.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeDate.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeDeadline.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeExternalKey.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeHierarchicalKey.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeExternalField.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeURL.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeBlob.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeImage.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeStopWatch.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeSubItem.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeOneWayPassword.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeTable.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributePropertySet.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeSet.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeEnumSet.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeClassAttCodeSet.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeQueryAttCodeSet.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeTagSet.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeFriendlyName.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeRedundancySettings.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeObsolescenceDate.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeCustomFields.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeArchiveFlag.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeArchiveDate.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeObsolescenceFlag.php');
require_once(APPROOT.'/sources/Core/AttributeDefinition/AttributeObsolescenceDate.php');
// Indexed array having two dimensions
// The PHP value is a hash array, it is stored as a TEXT column

View File

@@ -26,17 +26,54 @@ MetaModel::IncludeModule('application/query.class.inc.php');
MetaModel::IncludeModule('setup/moduleinstallation.class.inc.php');
MetaModel::IncludeModule('core/event.class.inc.php');
MetaModel::IncludeModule('core/action.class.inc.php');
MetaModel::IncludeModule('core/trigger.class.inc.php');
MetaModel::IncludeModule('core/bulkexport.class.inc.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/Event/Event.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/Event/EventNotification.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/Event/EventNotificationEmail.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/Event/EventIssue.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/Event/EventWebService.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/Event/EventRestService.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/Event/EventLoginUsage.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/Event/EventOnObject.php');
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/AsyncTask/ExecAsyncTask.php');
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/AsyncTask/AsyncTask.php');
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/AsyncTask/AsyncSendEmail.php');
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/AsyncTask/ExecAsyncTask.php');
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/AsyncTask/AsyncSendNewsroom.php');
MetaModel::IncludeModule(APPROOT.'/core/email.class.inc.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/Action.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/ActionNotification.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/ActionEmail.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/lnkTriggerAction.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/Trigger.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnAttributeBlobDownload.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnObject.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnObjectCreate.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnObjectDelete.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnObjectMention.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnObjectUpdate.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnPortalUpdate.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnStateChange.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnStateEnter.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnStateLeave.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/DataModel/TriggerAndAction/TriggerOnThresholdReached.php');
//MetaModel::IncludeModule('core/bulkexport.class.inc.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/BulkExport/BulkExport.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/BulkExport/BulkExportException.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/BulkExport/BulkExportMissingParameterException.php');
MetaModel::IncludeModule(APPROOT.'/sources/Application/BulkExport/BulkExportResultGC.php');
MetaModel::IncludeModule('core/ownershiplock.class.inc.php');
MetaModel::IncludeModule('core/tagsetfield.class.inc.php');
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/TagSetFieldData.php');
MetaModel::IncludeModule('synchro/synchrodatasource.class.inc.php');
MetaModel::IncludeModule('core/backgroundtask.class.inc.php');
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/BackgroundTask.php');
MetaModel::IncludeModule('core/inlineimage.class.inc.php');
MetaModel::IncludeModule('core/counter.class.inc.php');
MetaModel::IncludeModule('core/TemporaryObjectDescriptor.php');
//MetaModel::IncludeModule('core/counter.class.inc.php');
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/KeyValueStore.php');
MetaModel::IncludeModule(APPROOT.'/sources/Core/DataModel/TemporaryObjectDescriptor.php');
MetaModel::IncludeModule('webservices/webservices.basic.php');

File diff suppressed because it is too large Load Diff

View File

@@ -1,504 +0,0 @@
<?php
/**
* Copyright (C) 2013-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
*/
use Combodo\iTop\Application\WebPage\Page;
use Combodo\iTop\Application\WebPage\WebPage;
define('EXPORTER_DEFAULT_CHUNK_SIZE', 1000);
class BulkExportException extends Exception
{
protected $sLocalizedMessage;
public function __construct($message, $sLocalizedMessage, $code = 0, $previous = null)
{
parent::__construct($message, $code, $previous);
$this->sLocalizedMessage = $sLocalizedMessage;
}
public function GetLocalizedMessage()
{
return $this->sLocalizedMessage;
}
}
class BulkExportMissingParameterException extends BulkExportException
{
public function __construct($sFieldCode)
{
parent::__construct('Missing parameter: '.$sFieldCode, Dict::Format('Core:BulkExport:MissingParameter_Param', $sFieldCode));
}
}
/**
* Class BulkExport
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
class BulkExportResult extends DBObject
{
public static function Init()
{
$aParams = array
(
"category" => 'core/cmdb',
"key_type" => 'autoincrement',
"name_attcode" => array('created'),
"state_attcode" => '',
"reconc_keys" => array(),
"db_table" => 'priv_bulk_export_result',
"db_key_field" => 'id',
"db_finalclass_field" => '',
"display_template" => '',
);
MetaModel::Init_Params($aParams);
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())));
MetaModel::Init_AddAttribute(new AttributeString("temp_file_path", array("allowed_values"=>null, "sql"=>"temp_file_path", "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLongText("search", array("allowed_values"=>null, "sql"=>"search", "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLongText("status_info", array("allowed_values"=>null, "sql"=>"status_info", "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeBoolean("localize_output", array("allowed_values"=>null, "sql"=>"localize_output", "default_value"=>true, "is_null_allowed"=>true, "depends_on"=>array())));
}
/**
* @throws CoreUnexpectedValue
* @throws Exception
*/
public function ComputeValues()
{
$this->Set('user_id', UserRights::GetUserId());
}
}
/**
* Garbage collector for cleaning "old" export results from the database and the disk.
* This background process runs once per day and deletes the results of all exports which
* are older than one day.
*/
class BulkExportResultGC implements iBackgroundProcess
{
public function GetPeriodicity()
{
return 24*3600; // seconds
}
public function Process($iTimeLimit)
{
$sDateLimit = date(AttributeDateTime::GetSQLFormat(), time() - 24*3600); // Every BulkExportResult older than one day will be deleted
$sOQL = "SELECT BulkExportResult WHERE created < '$sDateLimit'";
$iProcessed = 0;
while (time() < $iTimeLimit)
{
// Next one ?
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('created' => true) /* order by*/, array(), null, 1 /* limit count */);
$oSet->OptimizeColumnLoad(array('BulkExportResult' => array('temp_file_path')));
$oResult = $oSet->Fetch();
if (is_null($oResult))
{
// Nothing to be done
break;
}
$iProcessed++;
@unlink($oResult->Get('temp_file_path'));
utils::PushArchiveMode(false);
$oResult->DBDelete();
utils::PopArchiveMode();
}
return "Cleaned $iProcessed old export results(s).";
}
}
/**
* Class BulkExport
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
abstract class BulkExport
{
protected $oSearch;
protected $iChunkSize;
protected $sFormatCode;
protected $aStatusInfo;
protected $oBulkExportResult;
protected $sTmpFile;
protected $bLocalizeOutput;
public function __construct()
{
$this->oSearch = null;
$this->iChunkSize = 0;
$this->sFormatCode = null;
$this->aStatusInfo = [
'show_obsolete_data' => utils::ShowObsoleteData(),
];
$this->oBulkExportResult = null;
$this->sTmpFile = '';
$this->bLocalizeOutput = false;
}
/**
* Find the first class capable of exporting the data in the given format
*
* @param string $sFormatCode The lowercase format (e.g. html, csv, spreadsheet, xlsx, xml, json, pdf...)
* @param DBSearch $oSearch The search/filter defining the set of objects to export or null when listing the supported formats
*
* @return BulkExport|null
* @throws ReflectionException
*/
static public function FindExporter($sFormatCode, $oSearch = null)
{
foreach(get_declared_classes() as $sPHPClass)
{
$oRefClass = new ReflectionClass($sPHPClass);
if ($oRefClass->isSubclassOf('BulkExport') && !$oRefClass->isAbstract())
{
/** @var BulkExport $oBulkExporter */
$oBulkExporter = new $sPHPClass();
if ($oBulkExporter->IsFormatSupported($sFormatCode, $oSearch))
{
if ($oSearch)
{
$oBulkExporter->SetObjectList($oSearch);
}
return $oBulkExporter;
}
}
}
return null;
}
/**
* Find the exporter corresponding to the given persistent token
*
* @param int $iPersistentToken The identifier of the BulkExportResult object storing the information
*
* @return BulkExport|null
* @throws ArchivedObjectException
* @throws CoreException
* @throws ReflectionException
*/
static public function FindExporterFromToken($iPersistentToken = null)
{
$oBulkExporter = null;
$oInfo = MetaModel::GetObject('BulkExportResult', $iPersistentToken, false);
if ($oInfo && ($oInfo->Get('user_id') == UserRights::GetUserId()))
{
$sFormatCode = $oInfo->Get('format');
$aStatusInfo = json_decode($oInfo->Get('status_info'),true);
$oSearch = DBObjectSearch::unserialize($oInfo->Get('search'));
$oSearch->SetShowObsoleteData($aStatusInfo['show_obsolete_data']);
$oBulkExporter = self::FindExporter($sFormatCode, $oSearch);
if ($oBulkExporter)
{
$oBulkExporter->SetFormat($sFormatCode);
$oBulkExporter->SetObjectList($oSearch);
$oBulkExporter->SetChunkSize($oInfo->Get('chunk_size'));
$oBulkExporter->SetStatusInfo($aStatusInfo);
$oBulkExporter->SetLocalizeOutput($oInfo->Get('localize_output'));
$oBulkExporter->sTmpFile = $oInfo->Get('temp_file_path');
$oBulkExporter->oBulkExportResult = $oInfo;
}
}
return $oBulkExporter;
}
/**
* @param $data
* @throws Exception
*/
public function AppendToTmpFile($data)
{
if ($this->sTmpFile == '')
{
$this->sTmpFile = $this->MakeTmpFile($this->GetFileExtension());
}
$hFile = fopen($this->sTmpFile, 'ab');
if ($hFile !== false)
{
fwrite($hFile, $data);
fclose($hFile);
}
}
public function GetTmpFilePath()
{
return $this->sTmpFile;
}
/**
* Lists all possible export formats. The output is a hash array in the form: 'format_code' => 'localized format label'
* @return array :string
*/
static public function FindSupportedFormats()
{
$aSupportedFormats = array();
foreach(get_declared_classes() as $sPHPClass)
{
$oRefClass = new ReflectionClass($sPHPClass);
if ($oRefClass->isSubClassOf('BulkExport') && !$oRefClass->isAbstract())
{
$oBulkExporter = new $sPHPClass;
$aFormats = $oBulkExporter->GetSupportedFormats();
$aSupportedFormats = array_merge($aSupportedFormats, $aFormats);
}
}
return $aSupportedFormats;
}
/**
* (non-PHPdoc)
* @see iBulkExport::SetChunkSize()
*/
public function SetChunkSize($iChunkSize)
{
$this->iChunkSize = $iChunkSize;
}
/**
* @param $bLocalizeOutput
*/
public function SetLocalizeOutput($bLocalizeOutput)
{
$this->bLocalizeOutput = $bLocalizeOutput;
}
/**
* (non-PHPdoc)
* @see iBulkExport::SetObjectList()
*/
public function SetObjectList(DBSearch $oSearch)
{
$oSearch->SetShowObsoleteData($this->aStatusInfo['show_obsolete_data']);
$this->oSearch = $oSearch;
}
public function SetFormat($sFormatCode)
{
$this->sFormatCode = $sFormatCode;
}
/**
* (non-PHPdoc)
* @see iBulkExport::IsFormatSupported()
*/
public function IsFormatSupported($sFormatCode, $oSearch = null)
{
return array_key_exists($sFormatCode, $this->GetSupportedFormats());
}
/**
* (non-PHPdoc)
* @see iBulkExport::GetSupportedFormats()
*/
public function GetSupportedFormats()
{
return array(); // return array('csv' => Dict::S('UI:ExportFormatCSV'));
}
public function SetHttpHeaders(WebPage $oPage)
{
}
/**
* @return string
*/
public function GetHeader()
{
return '';
}
abstract public function GetNextChunk(&$aStatus);
/**
* @return string
*/
public function GetFooter()
{
return '';
}
public function SaveState()
{
if ($this->oBulkExportResult === null)
{
$this->oBulkExportResult = new BulkExportResult();
$this->oBulkExportResult->Set('format', $this->sFormatCode);
$this->oBulkExportResult->Set('search', $this->oSearch->serialize());
$this->oBulkExportResult->Set('chunk_size', $this->iChunkSize);
$this->oBulkExportResult->Set('localize_output', $this->bLocalizeOutput);
}
$this->oBulkExportResult->Set('status_info', json_encode($this->GetStatusInfo()));
$this->oBulkExportResult->Set('temp_file_path', $this->sTmpFile);
utils::PushArchiveMode(false);
$ret = $this->oBulkExportResult->DBWrite();
utils::PopArchiveMode();
return $ret;
}
public function Cleanup()
{
if (($this->oBulkExportResult && (!$this->oBulkExportResult->IsNew())))
{
$sFilename = $this->oBulkExportResult->Get('temp_file_path');
if ($sFilename != '')
{
@unlink($sFilename);
}
utils::PushArchiveMode(false);
$this->oBulkExportResult->DBDelete();
utils::PopArchiveMode();
}
}
public function EnumFormParts()
{
return array();
}
/**
* @param WebPage $oP
* @param $sPartId
*
* @return UIContentBlock
*/
public function GetFormPart(WebPage $oP, $sPartId)
{
}
public function DisplayUsage(Page $oP)
{
}
public function ReadParameters()
{
$this->bLocalizeOutput = !((bool)utils::ReadParam('no_localize', 0, true, 'integer'));
}
public function GetResultAsHtml()
{
}
public function GetRawResult()
{
}
/**
* @return string
*/
public function GetMimeType()
{
return '';
}
/**
* @return string
*/
public function GetFileExtension()
{
return '';
}
public function GetCharacterSet()
{
return 'UTF-8';
}
public function GetStatistics()
{
}
public function SetFields($sFields)
{
}
public function GetDownloadFileName()
{
return Dict::Format('Core:BulkExportOf_Class', MetaModel::GetName($this->oSearch->GetClass())).'.'.$this->GetFileExtension();
}
public function SetStatusInfo($aStatusInfo)
{
$this->aStatusInfo = $aStatusInfo;
}
public function GetStatusInfo()
{
return $this->aStatusInfo;
}
/**
* @param $sExtension
* @return string
* @throws Exception
*/
protected function MakeTmpFile($sExtension)
{
if(!is_dir(utils::GetDataPath()."bulk_export"))
{
@mkdir(utils::GetDataPath()."bulk_export", 0777, true /* recursive */);
clearstatcache();
}
if (!is_writable(utils::GetDataPath()."bulk_export"))
{
throw new Exception('Data directory "'.utils::GetDataPath().'bulk_export" could not be written.');
}
$iNum = rand();
do
{
$iNum++;
$sToken = sprintf("%08x", $iNum);
$sFileName = utils::GetDataPath()."bulk_export/$sToken.".$sExtension;
$hFile = @fopen($sFileName, 'x');
}
while($hFile === false);
fclose($hFile);
return $sFileName;
}
}
// The built-in exports
require_once(APPROOT.'core/tabularbulkexport.class.inc.php');
require_once(APPROOT.'core/htmlbulkexport.class.inc.php');
if (extension_loaded('gd'))
{
// PDF export - via TCPDF - requires GD
require_once(APPROOT.'core/pdfbulkexport.class.inc.php');
}
require_once(APPROOT.'core/csvbulkexport.class.inc.php');
require_once(APPROOT.'core/excelbulkexport.class.inc.php');
require_once(APPROOT.'core/spreadsheetbulkexport.class.inc.php');
require_once(APPROOT.'core/xmlbulkexport.class.inc.php');

File diff suppressed because it is too large Load Diff

View File

@@ -40,9 +40,15 @@ require_once('dict.class.inc.php');
require_once('attributedef.class.inc.php');
require_once('stimulus.class.inc.php');
require_once('valuesetdef.class.inc.php');
require_once('MyHelpers.class.inc.php');
require_once(APPROOT.'/sources/Core/ValueSetDefinition/ValueSetDefinition.php');
require_once(APPROOT.'/sources/Core/ValueSetDefinition/ValueSetObjects.php');
require_once(APPROOT.'/sources/Core/ValueSetDefinition/ValueSetEnum.php');
require_once(APPROOT.'/sources/Core/ValueSetDefinition/ValueSetEnumPadded.php');
require_once(APPROOT.'/sources/Core/ValueSetDefinition/ValueSetRange.php');
require_once(APPROOT.'/sources/Core/ValueSetDefinition/ValueSetEnumClasses.php');
require_once('oql/expression.class.inc.php');
require_once('oql/oqlquery.class.inc.php');
require_once('oql/oqlexception.class.inc.php');
@@ -59,12 +65,41 @@ require_once('dbobject.class.php');
require_once('dbobjectset.class.php');
require_once('backgroundprocess.inc.php');
require_once('asynctask.class.inc.php');
require_once('dbproperty.class.inc.php');
//require_once('asynctask.class.inc.php');
require_once(APPROOT.'/sources/Core/DataModel/AsyncTask/ExecAsyncTask.php');
require_once(APPROOT.'/sources/Core/DataModel/AsyncTask/AsyncTask.php');
require_once(APPROOT.'/sources/Core/DataModel/AsyncTask/AsyncSendEmail.php');
require_once(APPROOT.'/sources/Core/DataModel/AsyncTask/ExecAsyncTask.php');
require_once(APPROOT.'/sources/Core/DataModel/AsyncTask/AsyncSendNewsroom.php');
require_once(APPROOT.'/sources/Core/DataModel/DBProperty.php');
// db change tracking data model
require_once('cmdbchange.class.inc.php');
require_once('cmdbchangeop.class.inc.php');
//require_once('cmdbchangeop.class.inc.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/iCMDBChangeOp.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOp.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpCreate.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpDelete.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpPlugin.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttribute.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeBlob.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeCaseLog.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeCustomFields.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeEncrypted.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeHTML.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeLinks.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeLinksAddRemove.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeLinksTune.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeLongText.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeOneWayPassword.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeScalar.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeTagSet.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeText.php');
require_once(APPROOT.'/sources/Core/DataModel/CMDBChange/CMDBChangeOpSetAttributeURL.php');
// customization data model
// Romain: temporary moved into application.inc.php (see explanations there)
@@ -77,7 +112,7 @@ require_once('cmdbchangeop.class.inc.php');
require_once('templatestring.class.inc.php');
require_once('csvparser.class.inc.php');
require_once('bulkchange.class.inc.php');
//require_once('bulkchange.class.inc.php');
/**
* A persistent object, which changes are accurately recorded

View File

@@ -42,6 +42,11 @@ class CMDBSource
const ENUM_DB_VENDOR_MARIADB = 'MariaDB';
const ENUM_DB_VENDOR_PERCONA = 'Percona';
/**
* @since 2.7.10 3.0.4 3.1.2 3.0.2 N°6889 constant creation
* @internal will be removed in a future version
*/
const MYSQL_DEFAULT_PORT = 3306;
/**
* Error: 1205 SQLSTATE: HY000 (ER_LOCK_WAIT_TIMEOUT)
@@ -215,7 +220,7 @@ class CMDBSource
* @param string $sServer server variable to update
* @param int|null $iPort port variable to update, will return null if nothing is specified in $sDbHost
*
* @since 2.7.10 3.0.4 3.1.2 3.2.0 N°6889 will return null in $iPort if port isn't present in $sDbHost.
* @since 2.7.10 3.0.4 3.1.2 3.2.0 N°6889 will return null in $iPort if port isn't present in $sDbHost. Use {@see MYSQL_DEFAULT_PORT} if needed
*
* @link http://php.net/manual/en/mysqli.persistconns.php documentation for the "p:" prefix (persistent connexion)
*/
@@ -358,6 +363,15 @@ class CMDBSource
return static::QueryToScalar('SELECT VERSION()', 0);
}
/**
* @deprecated Use `CMDBSource::GetDBVersion` instead.
* @uses mysqli_get_server_info
*/
public static function GetServerInfo()
{
return mysqli_get_server_info(DbConnectionWrapper::GetDbConnection());
}
/**
* Get the DB vendor between MySQL and its main forks
* @return string

View File

@@ -20,9 +20,6 @@
*/
use Combodo\iTop\Config\Validator\iTopConfigAstValidator;
use Combodo\iTop\Config\Validator\iTopConfigSyntaxValidator;
define('ITOP_APPLICATION', 'iTop');
define('ITOP_APPLICATION_SHORT', 'iTop');
@@ -52,7 +49,13 @@ define('ACCESS_READONLY', 0);
*/
require_once('attributedef.class.inc.php'); // For the defines
require_once('simplecrypt.class.inc.php');
require_once(APPROOT.'/sources/Application/SimpleCrypt/CryptEngine.php');
require_once(APPROOT.'/sources/Application/SimpleCrypt/SimpleCrypt.php');
require_once(APPROOT.'/sources/Application/SimpleCrypt/SimpleCryptMcryptEngine.php');
require_once(APPROOT.'/sources/Application/SimpleCrypt/SimpleCryptOpenSSLEngine.php');
require_once(APPROOT.'/sources/Application/SimpleCrypt/SimpleCryptOpenSSLMcryptCompatibilityEngine.php');
require_once(APPROOT.'/sources/Application/SimpleCrypt/SimpleCryptSimpleEngine.php');
require_once(APPROOT.'/sources/Application/SimpleCrypt/SimpleCryptSodiumEngine.php');
// was utf8 but it only supports BMP chars (https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html)
// so we switched to utf8mb4 in iTop 2.5, adding dependency to MySQL 5.5.3
@@ -1819,7 +1822,6 @@ class Config
return (array_key_exists($sPropCode, $this->m_aSettings));
}
/**
* @return string identifier that can be used for example to name WebStorage/SessionStorage keys (they
* are related to a whole domain, and a domain can host multiple itop)
@@ -2259,9 +2261,6 @@ class Config
$this->m_aModuleSettings[$sModule][$sProperty] = $value;
}
/**
* @deprecated 3.3.0 N°8190
*/
public function GetAddons()
{
if (array_key_exists("user rights", $this->m_aAddons)) {
@@ -2271,9 +2270,6 @@ class Config
}
}
/**
* @deprecated 3.3.0 N°8190
*/
public function SetAddons($aAddons)
{
$this->m_aAddons = $aAddons;
@@ -2852,8 +2848,20 @@ class Config
}
}
}
RunTimeEnvironment::CallInstallerHandler($aModuleInfo, "BeforeWritingConfig", [$this]);
if (isset($aModuleInfo['installer']))
{
$sModuleInstallerClass = $aModuleInfo['installer'];
if (!class_exists($sModuleInstallerClass))
{
throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not a PHP class - Module: ".$aModuleInfo['label']);
}
if (!is_subclass_of($sModuleInstallerClass, 'ModuleInstallerAPI'))
{
throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not derived from 'ModuleInstallerAPI' - Module: ".$aModuleInfo['label']);
}
$aCallSpec = array($sModuleInstallerClass, 'BeforeWritingConfig');
call_user_func_array($aCallSpec, array($this));
}
}
}
$this->SetAddOns($aAddOns);
@@ -3021,6 +3029,4 @@ class ConfigPlaceholdersResolver
IssueLog::Error($sErrorMessage, self::class, array($sSourceName, $sKey, $sDefault, $sWholeMask));
throw new ConfigException($sErrorMessage);
}
}

View File

@@ -1,251 +0,0 @@
<?php
/**
* Copyright (C) 2013-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
*/
/**
* Class ItopCounter
*
*/
final class ItopCounter
{
/**
* Key based counter.
* The counter is protected against concurrency script.
*
* @param $sCounterName
* @param null|callable $oNewObjectValueProvider optional callable that must return an integer. Used when no key is found
*
* @return int the counter starting at
* * `0` when no $oNewObjectValueProvider is given (or null)
* * `$oNewObjectValueProvider() + 1` otherwise
*
* @throws \CoreException
* @throws \MySQLException
* @throws \Exception
*/
public static function Inc($sCounterName, $oNewObjectValueProvider = null)
{
$sSelfClassName = self::class;
$sMutexKeyName = "{$sSelfClassName}-{$sCounterName}";
$oiTopMutex = new iTopMutex($sMutexKeyName);
$oiTopMutex->Lock();
$bIsInsideTransaction = CMDBSource::IsInsideTransaction();
if ($bIsInsideTransaction)
{
// # Transaction isolation hack:
// When inside a transaction, we need to open a new connection for the counter.
// So it is visible immediately to the connections outside of the transaction.
// Either way, the lock is not long enought, and there would be duplicate ref.
//
// SELECT ... FOR UPDATE would have also worked but with the cost of extra long lock (until the commit),
// we did not wanted this! As opening a short connection is less prone to starving than a long running one.
// Plus it would trigger way more deadlocks!
$hDBLink = self::InitMySQLSession();
}
else
{
$hDBLink = CMDBSource::GetMysqli();
}
try
{
$oFilter = DBObjectSearch::FromOQL('SELECT KeyValueStore WHERE key_name=:key_name AND namespace=:namespace', array(
'key_name' => $sCounterName,
'namespace' => $sSelfClassName,
));
$oAttDef = MetaModel::GetAttributeDef(KeyValueStore::class, 'value');
$aAttToLoad = array(KeyValueStore::class => array('value' => $oAttDef));
$sSql = $oFilter->MakeSelectQuery(array(), array(), $aAttToLoad);
$hResult = mysqli_query($hDBLink, $sSql);
$aCounter = mysqli_fetch_array($hResult, MYSQLI_NUM);
mysqli_free_result($hResult);
//Rebuild the filter, as the MakeSelectQuery polluted the orignal and it cannot be reused
$oFilter = DBObjectSearch::FromOQL('SELECT KeyValueStore WHERE key_name=:key_name AND namespace=:namespace', array(
'key_name' => $sCounterName,
'namespace' => $sSelfClassName,
));
if (is_null($aCounter))
{
if (null != $oNewObjectValueProvider)
{
$iComputedValue = $oNewObjectValueProvider();
}
else
{
$iComputedValue = 0;
}
$iCurrentValue = $iComputedValue + 1;
$aQueryParams = array(
'key_name' => $sCounterName,
'value' => "$iCurrentValue",
'namespace' => $sSelfClassName,
);
$sSql = $oFilter->MakeInsertQuery($aQueryParams);
}
else
{
$iCurrentValue = (int) $aCounter[1];
$iCurrentValue++;
$aQueryParams = array(
'value' => "$iCurrentValue",
);
$sSql = $oFilter->MakeUpdateQuery($aQueryParams);
}
$hResult = mysqli_query($hDBLink, $sSql);
}
catch(Exception $e)
{
IssueLog::Error($e->getMessage());
throw $e;
}
finally
{
if ($bIsInsideTransaction)
{
mysqli_close($hDBLink);
}
$oiTopMutex->Unlock();
}
return $iCurrentValue;
}
/**
* handle a counter for the root class of given $sLeafClass.
* If no counter exist initialize it with the `max(id) + 1`
*
*
*
* @param $sLeafClass
*
* @return int
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreOqlMultipleResultsForbiddenException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
* @throws \OQLException
*/
public static function IncClass($sLeafClass)
{
$sRootClass = MetaModel::GetRootClass($sLeafClass);
$oNewObjectCallback = function() use ($sRootClass)
{
$sRootTable = MetaModel::DBGetTable($sRootClass);
$sIdField = MetaModel::DBGetKey($sRootClass);
return CMDBSource::QueryToScalar("SELECT max(`$sIdField`) FROM `$sRootTable`");
};
return self::Inc($sRootClass, $oNewObjectCallback);
}
/**
* @return \mysqli
* @throws \ConfigException
* @throws \CoreException
* @throws \MySQLException
*/
private static function InitMySQLSession()
{
$oConfig = utils::GetConfig();
$sDBHost = $oConfig->Get('db_host');
$sDBUser = $oConfig->Get('db_user');
$sDBPwd = $oConfig->Get('db_pwd');
$sDBName = $oConfig->Get('db_name');
$bDBTlsEnabled = $oConfig->Get('db_tls.enabled');
$sDBTlsCA = $oConfig->Get('db_tls.ca');
$hDBLink = CMDBSource::GetMysqliInstance($sDBHost, $sDBUser, $sDBPwd, $sDBName, $bDBTlsEnabled, $sDBTlsCA, false);
if (!$hDBLink)
{
throw new MySQLException('Could not connect to the DB server '.mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno(), array('host' => $sDBHost, 'user' => $sDBUser));
}
return $hDBLink;
}
}
/**
* Persistent classes for a CMDB
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
class KeyValueStore extends DBObject
{
public static function Init()
{
$aParams = array(
'category' => '',
'key_type' => 'autoincrement',
'name_attcode' => array('key_name'),
'state_attcode' => '',
'reconc_keys' => array(''),
'db_table' => 'key_value_store',
'db_key_field' => 'id',
'db_finalclass_field' => '',
'indexes' => array (
array (
0 => 'key_name',
1 => 'namespace',
),
),);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("namespace", array("allowed_values"=>null, "sql"=>'namespace', "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array(), "always_load_in_tables"=>false)));
MetaModel::Init_AddAttribute(new AttributeString("key_name", array("allowed_values"=>null, "sql"=>'key_name', "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array(), "always_load_in_tables"=>false)));
MetaModel::Init_AddAttribute(new AttributeString("value", array("allowed_values"=>null, "sql"=>'value', "default_value"=>'0', "is_null_allowed"=>false, "depends_on"=>array(), "always_load_in_tables"=>false)));
MetaModel::Init_SetZListItems('details', array (
0 => 'key_name',
1 => 'value',
2 => 'namespace',
));
MetaModel::Init_SetZListItems('standard_search', array (
0 => 'key_name',
1 => 'value',
2 => 'namespace',
));
MetaModel::Init_SetZListItems('list', array (
0 => 'key_name',
1 => 'value',
2 => 'namespace',
));
;
}
}

View File

@@ -62,7 +62,7 @@ require_once('mutex.class.inc.php');
/**
* A persistent object, as defined by the metamodel
* A persistent object, as defined by the metamodel
*
* @package iTopORM
* @api
@@ -314,9 +314,9 @@ abstract class DBObject implements iDisplay
/**
* Whether the object is already persisted in DB or not.
*
*
* @api
*
*
* @return bool
*/
public function IsNew()
@@ -326,9 +326,9 @@ abstract class DBObject implements iDisplay
/**
* Returns an Id for memory objects
*
*
* @internal
*
*
* @param string $sClass
*
* @return int
@@ -365,7 +365,7 @@ abstract class DBObject implements iDisplay
$sRet .= "<b title=\"$sRootClass\">$sClass</b>::$iPKey ($sFriendlyname)<br/>\n";
return $sRet;
}
/**
* Alias of DBObject::Reload()
*
@@ -388,7 +388,7 @@ abstract class DBObject implements iDisplay
*
* @internal
* @see m_bFullyLoaded
*
*
* @return bool
* @throws CoreException
*/
@@ -411,9 +411,11 @@ abstract class DBObject implements iDisplay
* This is mostly used after a lazy load (automatically performed by the framework)
* This will erase any pending changes.
*
* @param bool $bAllowAllData @deprecated This parameter is ignored!!
*
* @throws CoreException
*/
public function Reload()
public function Reload($bAllowAllData = false)
{
assert($this->m_bIsInDB);
$this->FireEvent(EVENT_DB_OBJECT_RELOAD);
@@ -509,7 +511,7 @@ abstract class DBObject implements iDisplay
{
$aAttList = $aAttToLoad[$sClassAlias];
}
foreach($aAttList as $sAttCode=>$oAttDef)
{
// Skip links (could not be loaded by the mean of this query)
@@ -569,7 +571,7 @@ abstract class DBObject implements iDisplay
$bFullyLoaded = false;
}
}
// Load extended data
if ($aExtendedDataSpec != null)
{
@@ -593,7 +595,7 @@ abstract class DBObject implements iDisplay
*
* @internal
* @see Set()
*
*
* @param string $sAttCode
* @param mixed $value
*/
@@ -848,11 +850,11 @@ abstract class DBObject implements iDisplay
/**
* Get the label of an attribute.
*
*
* Shortcut to the field's AttributeDefinition->GetLabel()
*
* @api
*
*
* @param string $sAttCode
*
* @return string
@@ -925,7 +927,7 @@ abstract class DBObject implements iDisplay
*
* @internal
* @see Get
*
*
* @param string $sAttCode
*
* @return int|mixed|null
@@ -1030,7 +1032,7 @@ abstract class DBObject implements iDisplay
* Returns the default value of the $sAttCode.
*
* Returns the default value of the given attribute.
*
*
* @internal
*
* @param string $sAttCode
@@ -1051,12 +1053,12 @@ abstract class DBObject implements iDisplay
* @internal
*
* @return array|null
*/
*/
public function GetExtendedData()
{
return $this->m_aExtendedData;
}
/**
* Set the HighlightCode
*
@@ -1078,7 +1080,7 @@ abstract class DBObject implements iDisplay
{
$fCurrentRank = $aHighlightScale[$this->m_sHighlightCode]['rank'];
}
if (array_key_exists($sCode, $aHighlightScale))
{
$fRank = $aHighlightScale[$sCode]['rank'];
@@ -1088,13 +1090,13 @@ abstract class DBObject implements iDisplay
}
}
}
/**
* Get the current HighlightCode
*
*
* @internal
* @used-by DBObject::ComputeHighlightCode()
*
*
* @return string|null The Hightlight code (null if none set, meaning rank = 0)
*/
protected function GetHighlightCode()
@@ -1143,7 +1145,7 @@ abstract class DBObject implements iDisplay
* corresponding to the external key and getting the value from it
*
* UNUSED ?
*
*
* @internal
* @todo: check if this is dead code.
*
@@ -1214,7 +1216,7 @@ abstract class DBObject implements iDisplay
/**
* @api
*
*
* @param string $sAttCode
* @param bool $bLocalize
*
@@ -1260,11 +1262,11 @@ abstract class DBObject implements iDisplay
/**
* Get the value as it must be in the edit areas (forms)
*
*
* Makes a raw text representation of the value.
*
* @internal
*
*
* @param string $sAttCode
*
* @return int|mixed|string
@@ -1294,7 +1296,7 @@ abstract class DBObject implements iDisplay
else
{
$sEditValue = 0;
}
}
}
else
{
@@ -1310,14 +1312,14 @@ abstract class DBObject implements iDisplay
/**
* Get $sAttCode formatted as XML
*
*
* The returned value is a text that is suitable for insertion into an XML node.
* Depending on the type of attribute, the returned text is either:
* * A literal, with XML entities already escaped,
* * XML
*
* @api
*
*
* @param string $sAttCode
* @param bool $bLocalize
*
@@ -1355,10 +1357,10 @@ abstract class DBObject implements iDisplay
}
/**
*
*
* @see GetAsHTML()
* @see GetOriginal()
*
*
* @param string $sAttCode
* @param bool $bLocalize
*
@@ -1533,7 +1535,7 @@ abstract class DBObject implements iDisplay
/**
* @internal
*
*
* @param string $sClass
*
* @return mixed
@@ -1588,7 +1590,7 @@ abstract class DBObject implements iDisplay
* Get the id
*
* @api
*
*
* @return string|null
*/
public function GetKey()
@@ -1599,7 +1601,7 @@ abstract class DBObject implements iDisplay
/**
* Primary key Setter
* Usable only for not yet persisted DBObjects
*
*
* @internal
*
* @param int $iNewKey the desired identifier
@@ -1612,7 +1614,7 @@ abstract class DBObject implements iDisplay
{
throw new CoreException("An object id must be an integer value ($iNewKey)");
}
if ($this->m_bIsInDB && !empty($this->m_iKey) && ($this->m_iKey != $iNewKey))
{
throw new CoreException("Changing the key ({$this->m_iKey} to $iNewKey) on an object (class {".get_class($this).") wich already exists in the Database");
@@ -1622,7 +1624,7 @@ abstract class DBObject implements iDisplay
/**
* Get the icon representing this object
*
*
* @api
*
* @param boolean $bImgTag If true the result is a full IMG tag (or an empty string if no icon is defined)
@@ -1712,7 +1714,7 @@ abstract class DBObject implements iDisplay
*
* Returns the label as defined in the dictionary for the language of the current user
*
* @api
* @api
*
* @return string (empty for default name scheme)
*/
@@ -1779,7 +1781,7 @@ abstract class DBObject implements iDisplay
/**
* Helper to get the state
*
*
* @api
*
* @return mixed|string '' if no state attribute, object representing its value otherwise
@@ -1801,9 +1803,9 @@ abstract class DBObject implements iDisplay
/**
* Get the label (raw text) of the current state
* helper for MetaModel::GetStateLabel()
*
*
* @api
*
*
* @return mixed|string
*
* @throws ArchivedObjectException
@@ -1850,7 +1852,7 @@ abstract class DBObject implements iDisplay
* Define attributes read-only from the end-user perspective
*
* @return array|null List of attcodes
*/
*/
public static function GetReadOnlyAttributes()
{
return null;
@@ -1859,14 +1861,14 @@ abstract class DBObject implements iDisplay
/**
* Get predefined objects
*
*
* The predefined objects will be synchronized with the DB at each install/upgrade
* As soon as a class has predefined objects, then nobody can create nor delete objects
*
* @internal
*
* @return array An array of id => array of attcode => php value(so-called "real value": integer, string, ormDocument, DBObjectSet, etc.)
*/
*/
public static function GetPredefinedObjects()
{
return null;
@@ -1995,7 +1997,7 @@ abstract class DBObject implements iDisplay
* Note: Attributes (and flags) from the target state and the transition are combined.
*
* @internal
*
*
* @param string $sStimulus
* @param string $sOriginState Default is current state
*
@@ -2195,7 +2197,7 @@ abstract class DBObject implements iDisplay
/**
* @internal
*
*
* @throws \CoreException
* @throws \OQLException
*
@@ -5321,7 +5323,7 @@ abstract class DBObject implements iDisplay
// Keep track of link changes
//
if (($oLinkSet->GetTrackingLevel() & LINKSET_TRACKING_DETAILS) == 0) continue;
$iLinkSetOwnerId = $this->Get($sExtKeyAttCode);
$oMyChangeOp = $this->PrepareChangeOpLinkSet($iLinkSetOwnerId, $oLinkSet, 'CMDBChangeOpSetAttributeLinksTune');
if ($oMyChangeOp)
@@ -5518,6 +5520,27 @@ abstract class DBObject implements iDisplay
set_time_limit(intval($iPreviousTimeLimit));
}
/**
* Caching relying on an object set is not efficient since 2.0.3
* Use GetSynchroData instead
*
* Get all the synchro replica related to this object
*
* @internal
* @deprecated
*
* @return DBObjectSet Set with two columns: R=SynchroReplica S=SynchroDataSource
* @throws \OQLException
*/
public function GetMasterReplica()
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod();
$sOQL = "SELECT replica,datasource FROM SynchroReplica AS replica JOIN SynchroDataSource AS datasource ON replica.sync_source_id=datasource.id WHERE replica.dest_class = :dest_class AND replica.dest_id = :dest_id";
$oReplicaSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL), array() /* order by*/, array('dest_class' => get_class($this), 'dest_id' => $this->GetKey()));
return $oReplicaSet;
}
/**
* Get all the synchro data related to this object
*

View File

@@ -236,6 +236,78 @@ abstract class DBSearch
*/
abstract public function IsAny();
/**
* @internal
* @deprecated use ToOQL() instead
* @return string
*/
public function Describe()
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use ToOQL() instead');
return 'deprecated - use ToOQL() instead';
}
/**
* @internal
* @deprecated use ToOQL() instead
* @return string
*/
public function DescribeConditionPointTo($sExtKeyAttCode, $aPointingTo)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use ToOQL() instead');
return 'deprecated - use ToOQL() instead';
}
/**
* @internal
* @deprecated use ToOQL() instead
* @return string
*/
public function DescribeConditionRefBy($sForeignClass, $sForeignExtKeyAttCode)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use ToOQL() instead');
return 'deprecated - use ToOQL() instead';
}
/**
* @internal
* @deprecated use ToOQL() instead
* @return string
*/
public function DescribeConditionRelTo($aRelInfo)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use ToOQL() instead');
return 'deprecated - use ToOQL() instead';
}
/**
* @internal
* @deprecated use ToOQL() instead
* @return string
*/
public function DescribeConditions()
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use ToOQL() instead');
return 'deprecated - use ToOQL() instead';
}
/**
* @internal
* @deprecated use ToOQL() instead
* @return string
*/
public function __DescribeHTML()
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use ToOQL() instead');
return 'deprecated - use ToOQL() instead';
}
/**
* @internal
* @return mixed
@@ -1644,6 +1716,16 @@ abstract class DBSearch
return $this->ToOQL(true);
}
/**
* @return array{\VariableExpression}
*
* @deprecated use DBSearch::GetExpectedArguments() instead
*/
public function ListParameters(): array
{
return $this->GetExpectedArguments();
}
/**
* Get parameters from the condition expression(s)
*

View File

@@ -114,6 +114,9 @@ class EMail implements iEMail
* @param string $sSerializedMessage The serialized representation of the message
*
* @return \Email
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \Symfony\Component\CssSelector\Exception\SyntaxErrorException
*/
public static function UnSerializeV2($sSerializedMessage)
{

View File

@@ -1,426 +0,0 @@
<?php
use Combodo\iTop\Application\WebPage\WebPage;
/**
* Copyright (C) 2013-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
*/
class Event extends DBObject implements iDisplay
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_event",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"order_by_default" => array('date' => false)
);
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"=>"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())));
// Display lists
MetaModel::Init_SetZListItems('details', array('date', 'message', 'userinfo')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'finalclass', 'message')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
/**
* Maps the given context parameter name to the appropriate filter/search code for this class
* @param string $sContextParam Name of the context parameter, i.e. 'org_id'
* @return string Filter code, i.e. 'customer_id'
*/
public static function MapContextParam($sContextParam)
{
if ($sContextParam == 'menu')
{
return null;
}
else
{
return $sContextParam;
}
}
/**
* This function returns a 'hilight' CSS class, used to hilight a given row in a table
* There are currently (i.e defined in the CSS) 4 possible values HILIGHT_CLASS_CRITICAL,
* HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE
* To Be overridden by derived classes
* @param void
* @return String The desired higlight class for the object/row
*/
public function GetHilightClass()
{
// Possible return values are:
// HILIGHT_CLASS_CRITICAL, HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE
return HILIGHT_CLASS_NONE; // Not hilighted by default
}
public static function GetUIPage()
{
return 'UI.php';
}
function DisplayDetails(WebPage $oPage, $bEditMode = false)
{
// Object's details
//$this->DisplayBareHeader($oPage, $bEditMode);
$oPage->AddTabContainer(OBJECT_PROPERTIES_TAB);
$oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB);
$oPage->SetCurrentTab('UI:PropertiesTab');
$this->DisplayBareProperties($oPage, $bEditMode);
}
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
{
if ($bEditMode) return array(); // Not editable
$aDetails = array();
$sClass = get_class($this);
$aZList = MetaModel::FlattenZlist(MetaModel::GetZListItems($sClass, 'details'));
foreach ($aZList as $sAttCode) {
$sDisplayValue = $this->GetAsHTML($sAttCode);
$aDetails[] = array('label' => '<span title="'.MetaModel::GetDescription($sClass, $sAttCode).'">'.MetaModel::GetLabel($sClass, $sAttCode).'</span>', 'value' => $sDisplayValue);
}
$oPage->Details($aDetails);
return array();
}
}
class EventNotification extends Event
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_event_notification",
"db_key_field" => "id",
"db_finalclass_field" => "",
"order_by_default" => array('date' => false),
'indexes' => array(
array( 'object_class', 'object_id'),
)
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("trigger_id", array("targetclass"=>"Trigger", "jointype"=> "", "allowed_values"=>null, "sql"=>"trigger_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", array("targetclass" => "Action", "jointype" => "", "allowed_values" => null, "sql" => "action_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeInteger("object_id", array("allowed_values" => null, "sql" => "object_id", "default_value" => 0, "is_null_allowed" => false, "depends_on" => array())));
//@since 3.2.0
MetaModel::Init_AddAttribute(new AttributeClass("object_class", array("class_category"=>"", "more_values"=>"", "sql"=>"object_class", "default_value"=>null, "is_null_allowed"=>true /*to avoid setting AbstractResource as default in database*/, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('date', 'message', 'userinfo', 'trigger_id', 'action_id', 'object_class', 'object_id')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'message')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
class EventNotificationEmail extends EventNotification
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_event_email",
"db_key_field" => "id",
"db_finalclass_field" => "",
"order_by_default" => array('date' => false)
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("cc", array("allowed_values"=>null, "sql"=>"cc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("bcc", array("allowed_values"=>null, "sql"=>"bcc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("from", array("allowed_values"=>null, "sql"=>"from", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeHTML("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeTable("attachments", array("allowed_values"=>null, "sql"=>"attachments", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'message', 'trigger_id', 'action_id', 'object_class', 'object_id', 'to', 'cc', 'bcc', 'from', 'subject', 'body', 'attachments')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'message', 'to', 'subject', 'attachments')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
class EventIssue extends Event
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_event_issue",
"db_key_field" => "id",
"db_finalclass_field" => "",
"order_by_default" => array('date' => false)
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("issue", array("allowed_values"=>null, "sql"=>"issue", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("impact", array("allowed_values"=>null, "sql"=>"impact", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("page", array("allowed_values"=>null, "sql"=>"page", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributePropertySet("arguments_post", array("allowed_values"=>null, "sql"=>"arguments_post", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributePropertySet("arguments_get", array("allowed_values"=>null, "sql"=>"arguments_get", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeTable("callstack", array("allowed_values"=>null, "sql"=>"callstack", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributePropertySet("data", array("allowed_values"=>null, "sql"=>"data", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('date', 'message', 'userinfo', 'issue', 'impact', 'page', 'arguments_post', 'arguments_get', 'callstack', 'data')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'issue', 'impact')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
protected function OnInsert()
{
// Init page information: name, arguments
//
$this->Set('page', @$GLOBALS['_SERVER']['SCRIPT_NAME']);
if (strlen($this->Get('userinfo')) == 0) {
$this->Set('userinfo', UserRights::GetUserId());
}
if (array_key_exists('_GET', $GLOBALS) && is_array($GLOBALS['_GET']))
{
$this->Set('arguments_get', $this->SanitizeRequestParams($GLOBALS['_GET']));
}
else
{
$this->Set('arguments_get', array());
}
if (array_key_exists('_POST', $GLOBALS) && is_array($GLOBALS['_POST']))
{
$this->Set('arguments_post', $this->SanitizeRequestParams($GLOBALS['_POST']));
} else {
$this->Set('arguments_post', array());
}
$sLength = mb_strlen($this->Get('issue'));
if ($sLength > 255) {
$this->Set('issue', mb_substr($this->Get('issue'), 0, 210)." -truncated ($sLength chars)");
}
$sLength = mb_strlen($this->Get('impact'));
if ($sLength > 255) {
$this->Set('impact', mb_substr($this->Get('impact'), 0, 210)." -truncated ($sLength chars)");
}
$sLength = mb_strlen($this->Get('page'));
if ($sLength > 255) {
$this->Set('page', mb_substr($this->Get('page'), 0, 210)." -truncated ($sLength chars)");
}
}
protected function SanitizeRequestParams(array $aParams): array
{
$aSanitizedParams = [];
foreach ($aParams as $sKey => $sValue) {
if (is_string($sValue)) {
if (stristr($sKey, 'pwd') !== false || stristr($sKey, 'passwd') !== false || stristr($sKey, 'password') !== false) {
$aSanitizedParams[$sKey] = '****';
} elseif (mb_strlen($sValue) < 256) {
$aSanitizedParams[$sKey] = $sValue;
} else {
$aSanitizedParams[$sKey] = '!long string: '.mb_strlen($sValue).' chars';
}
} else {
// Not a string (avoid warnings in case the value cannot be easily cast into a string)
$aSanitizedParams[$sKey] = @(string)$sValue;
}
}
return $aSanitizedParams;
}
}
class EventWebService extends Event
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_event_webservice",
"db_key_field" => "id",
"db_finalclass_field" => "",
"order_by_default" => array('date' => false)
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("verb", array("allowed_values"=>null, "sql"=>"verb", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
//MetaModel::Init_AddAttribute(new AttributeStructure("arguments", array("allowed_values"=>null, "sql"=>"data", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeBoolean("result", array("allowed_values"=>null, "sql"=>"result", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("log_info", array("allowed_values"=>null, "sql"=>"log_info", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("log_warning", array("allowed_values"=>null, "sql"=>"log_warning", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("log_error", array("allowed_values"=>null, "sql"=>"log_error", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("data", array("allowed_values"=>null, "sql"=>"data", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'verb', 'result', 'log_info', 'log_warning', 'log_error', 'data')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'verb', 'result')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
class EventRestService extends Event
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_event_restservice",
"db_key_field" => "id",
"db_finalclass_field" => "",
"order_by_default" => array('date' => false)
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("operation", array("allowed_values"=>null, "sql"=>"operation", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("version", array("allowed_values"=>null, "sql"=>"version", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("json_input", array("allowed_values"=>null, "sql"=>"json_input", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("code", array("allowed_values"=>null, "sql"=>"code", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("json_output", array("allowed_values"=>null, "sql"=>"json_output", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("provider", array("allowed_values"=>null, "sql"=>"provider", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'operation', 'version', 'json_input', 'message', 'code', 'json_output', 'provider')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'operation', 'message')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
class EventLoginUsage extends Event
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_event_loginusage",
"db_key_field" => "id",
"db_finalclass_field" => "",
"order_by_default" => array('date' => false)
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_SILENT, "depends_on"=>array())));
$aZList = array('date', 'user_id');
if (MetaModel::IsValidAttCode('Contact', 'name'))
{
MetaModel::Init_AddAttribute(new AttributeExternalField("contact_name", array("allowed_values"=>null, "extkey_attcode"=>"user_id", "target_attcode"=>"contactid", "is_null_allowed"=>true, "depends_on"=>array())));
$aZList[] = 'contact_name';
}
if (MetaModel::IsValidAttCode('Contact', 'email'))
{
MetaModel::Init_AddAttribute(new AttributeExternalField("contact_email", array("allowed_values"=>null, "extkey_attcode"=>"user_id", "target_attcode"=>"email", "is_null_allowed"=>true, "depends_on"=>array())));
$aZList[] = 'contact_email';
}
// Display lists
MetaModel::Init_SetZListItems('details', array_merge($aZList, array('userinfo', 'message'))); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array_merge($aZList, array('userinfo'))); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', $aZList); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
class EventOnObject extends Event
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_event_onobject",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
"order_by_default" => array('date' => false)
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("obj_class", array("allowed_values"=>null, "sql"=>"obj_class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("obj_key", array("allowed_values"=>null, "sql"=>"obj_key", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'obj_class', 'obj_key', 'message')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'obj_class', 'obj_key', 'message')); // Attributes to be displayed for a list
}
}

View File

@@ -110,7 +110,7 @@ class InlineImage extends DBObject
$aCallSpec = array($sClass, 'MapContextParam');
if (is_callable($aCallSpec))
{
$sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter
$sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter
if (MetaModel::IsValidAttCode($sClass, $sAttCode))
{
$iOrgId = $oItem->Get($sAttCode);
@@ -146,7 +146,7 @@ class InlineImage extends DBObject
$aCallSpec = array($sClass, 'MapContextParam');
if (is_callable($aCallSpec))
{
$sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter
$sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter
if (MetaModel::IsValidAttCode($sClass, $sAttCode))
{
// Second: check that the organization CAN be fetched from the current user
@@ -156,7 +156,7 @@ class InlineImage extends DBObject
$aCallSpec = array($sClass, 'MapContextParam');
if (is_callable($aCallSpec))
{
$sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter
$sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter
if (MetaModel::IsValidAttCode($sClass, $sAttCode))
{
// OK - try it
@@ -192,7 +192,7 @@ class InlineImage extends DBObject
if (!is_null($iTransactionId))
{
// Attach new (temporary) inline images
$sTempId = utils::GetUploadTempId($iTransactionId);
// The object is being created from a form, check if there are pending inline images for this object
$sOQL = 'SELECT InlineImage WHERE temp_id = :temp_id';
@@ -366,10 +366,10 @@ CombodoInlineImage.FixImagesWidth();
JS
;
}
return $sJS;
}
/**
* Check if an the given mimeType is an image that can be processed by the system
*
@@ -382,7 +382,7 @@ JS
public static function IsImage($sMimeType)
{
if (!function_exists('gd_info')) return false; // no image processing capability on this system
$bRet = false;
$aInfo = gd_info(); // What are the capabilities
switch($sMimeType)
@@ -390,19 +390,19 @@ JS
case 'image/gif':
return $aInfo['GIF Read Support'];
break;
case 'image/jpeg':
return $aInfo['JPEG Support'];
break;
case 'image/png':
return $aInfo['PNG Support'];
break;
}
return $bRet;
}
/**
* Resize an image so that it fits the maximum width/height defined in the config file
* @param ormDocument $oImage The original image stored as an array (content / mimetype / filename)
@@ -444,7 +444,7 @@ JS
}
return $sRet;
}
/**
* Get the fragment of javascript needed to complete the initialization of
* CKEditor when creating/modifying an object

View File

@@ -26,7 +26,14 @@ require_once APPROOT.'core/modulehandler.class.inc.php';
require_once APPROOT.'core/querymodifier.class.inc.php';
require_once APPROOT.'core/metamodelmodifier.inc.php';
require_once APPROOT.'core/computing.inc.php';
require_once APPROOT.'core/relationgraph.class.inc.php';
//require_once APPROOT.'core/relationgraph.class.inc.php';
require_once(APPROOT.'/sources/Core/RelationGraph/RelationEdge.php');
require_once(APPROOT.'/sources/Core/RelationGraph/RelationGraph.php');
require_once(APPROOT.'/sources/Core/RelationGraph/RelationObjectNode.php');
require_once(APPROOT.'/sources/Core/RelationGraph/RelationRedundancyNode.php');
require_once APPROOT.'core/apc-compat.php';
require_once APPROOT.'core/expressioncache.class.inc.php';
@@ -2105,6 +2112,55 @@ abstract class MetaModel
*/
private static $m_aRelationInfos = array();
/**
* @deprecated Use EnumRelationsEx instead
*
* @param string $sClass
*
* @return array multitype:string unknown |Ambigous <string, multitype:>
* @throws \CoreException
* @throws \Exception
* @throws \OQLException
*/
public static function EnumRelations($sClass = '')
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('Use EnumRelationsEx instead');
$aResult = array_keys(self::$m_aRelationInfos);
if (!empty($sClass)) {
// Return only the relations that have a meaning (i.e. for which at least one query is defined)
// for the specified class
$aClassRelations = array();
foreach ($aResult as $sRelCode) {
$aQueriesDown = self::EnumRelationQueries($sClass, $sRelCode);
if (count($aQueriesDown) > 0) {
$aClassRelations[] = $sRelCode;
}
// Temporary patch: until the impact analysis GUI gets rewritten,
// let's consider that "depends on" is equivalent to "impacts/up"
// The current patch has been implemented in DBObject and MetaModel
if ($sRelCode == 'impacts') {
$aQueriesUp = self::EnumRelationQueries($sClass, 'impacts', false);
if (count($aQueriesUp) > 0)
{
$aClassRelations[] = 'depends on';
}
}
}
return $aClassRelations;
}
// Temporary patch: until the impact analysis GUI gets rewritten,
// let's consider that "depends on" is equivalent to "impacts/up"
// The current patch has been implemented in DBObject and MetaModel
if (in_array('impacts', $aResult))
{
$aResult[] = 'depends on';
}
return $aResult;
}
/**
* @param string $sClass
*
@@ -5094,7 +5150,7 @@ abstract class MetaModel
*/
protected static function DBCreateViews()
{
[$aErrors, $aSugFix] = self::DBCleanLegacyViews();
[$aErrors, $aSugFix] = self::DBCheckViews();
foreach($aSugFix as $sClass => $aTarget)
{
@@ -5740,18 +5796,18 @@ abstract class MetaModel
/**
* @internal
* @deprecated will be remove when 2.7 will not be supported anymore
* @deprecated 2.7.0 N°2369 Method will not be removed any time soon as we still need to drop view if the instance is migrating from an iTop 2.x to an iTop 3.0 or newer, even if they skip iTop 3.0.
* @since 3.0.0 Does not recreate SQL views, only drops them. Method has not been renamed to avoid regressions
*
* @return array
* @throws \CoreException
* @throws \Exception
* @throws \MissingQueryArgument
*/
public static function DBCleanLegacyViews()
public static function DBCheckViews()
{
$aErrors = [];
$aSugFix = [];
$aErrors = array();
$aSugFix = array();
// Reporting views (must be created after any other table)
//
@@ -5766,7 +5822,7 @@ abstract class MetaModel
}
}
return [$aErrors, $aSugFix];
return array($aErrors, $aSugFix);
}
/**
@@ -6978,7 +7034,7 @@ abstract class MetaModel
* @param array $aParams
* @param bool $bAllowAllData
*
* @return \DBObject|null
* @return \DBObject
* @throws \OQLException
*/
public static function GetObjectFromOQL($sQuery, $aParams = null, $bAllowAllData = false)
@@ -7460,6 +7516,42 @@ abstract class MetaModel
SetupUtils::rrmdir(utils::GetCachePath($sEnvironment));
}
/**
* @internal
* @param string $sEnvironmentId
* @deprecated 3.2.1
*/
public static function ResetCache($sEnvironmentId = null)
{
if (is_null($sEnvironmentId))
{
$sEnvironmentId = MetaModel::GetEnvironmentId();
}
$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();
}
}
/**
* Given a field spec, get the most relevant (unique) representation
* Examples for a user request:
@@ -7624,6 +7716,7 @@ abstract class MetaModel
'iLoginUIExtension',
'iPreferencesExtension',
'iApplicationUIExtension',
'iApplicationObjectExtension',
'iPopupMenuExtension',
'iPageUIBlockExtension',
'iBackofficeLinkedScriptsExtension',

View File

@@ -495,8 +495,8 @@ class OqlObjectQuery extends OqlQuery
{
throw new OqlNormalizeException('Unknown class in join condition (right expression)', $sSourceQuery, $oRightField->GetParentDetails(), array_keys($aAliases));
}
$aExtKeys = $oModelReflection->ListAttributes($aAliases[$sFromClass], \Combodo\iTop\Core\AttributeDefinition\AttributeExternalKey::class);
$aObjKeys = $oModelReflection->ListAttributes($aAliases[$sFromClass], \Combodo\iTop\Core\AttributeDefinition\AttributeObjectKey::class);
$aExtKeys = $oModelReflection->ListAttributes($aAliases[$sFromClass], 'AttributeExternalKey');
$aObjKeys = $oModelReflection->ListAttributes($aAliases[$sFromClass], 'AttributeObjectKey');
$aAllKeys = array_merge($aExtKeys, $aObjKeys);
if (!array_key_exists($sExtKeyAttCode, $aAllKeys))
{
@@ -557,7 +557,7 @@ class OqlObjectQuery extends OqlQuery
}
$aAttList = $oModelReflection->ListAttributes($aAliases[$sFromClass]);
$sAttType = $aAttList[$sExtKeyAttCode];
if(($iOperatorCode != TREE_OPERATOR_EQUALS) && !is_subclass_of($sAttType, \Combodo\iTop\Core\AttributeDefinition\AttributeHierarchicalKey::class) && ($sAttType != \Combodo\iTop\Core\AttributeDefinition\AttributeHierarchicalKey::class))
if(($iOperatorCode != TREE_OPERATOR_EQUALS) && !is_subclass_of($sAttType, 'AttributeHierarchicalKey') && ($sAttType != 'AttributeHierarchicalKey'))
{
throw new OqlNormalizeException("The specified tree operator $sOperator is not applicable to the key", $sSourceQuery, $oLeftField->GetNameDetails());
}

View File

@@ -1,425 +0,0 @@
<?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/>
/**
* SimpleCrypt Class - crypto helpers
* Simple encryption of strings, uses mcrypt or degrades to a pure PHP
* implementation when mcrypt is not present.
* Based on Miguel Ros' work found at:
* http://rossoft.wordpress.com/2006/05/22/simple-encryption-class/
*
* Usage:
* $oSimpleCrypt = new SimpleCrypt();
* $encrypted = $oSimpleCrypt->encrypt('a_key','the_text');
* $sClearText = $oSimpleCrypt->decrypt('a_key',$encrypted);
*
* The result is $plain equals to 'the_text'
*
* You can use a different engine if you don't have Mcrypt:
* $oSimpleCrypt = new SimpleCrypt('Simple');
*
* A string encrypted with one engine can't be decrypted with
* a different one even if the key is the same.
*
* @author Miguel Ros <rossoft@gmail.com>
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
class SimpleCrypt
{
/**
* @var \SimpleCrypt
* @since 3.1.0 N°5388
*/
protected $oEngine;
public static function GetNewDefaultParams()
{
if(function_exists('sodium_crypto_secretbox_open') && function_exists('random_bytes')){
$sEngineName = 'Sodium';
}
else if (function_exists('openssl_decrypt'))
{
$sEngineName = 'OpenSSL';
}
else if(function_exists('mcrypt_module_open')){
$sEngineName = 'Mcrypt';
}
else
{
$sEngineName = 'Simple';
}
$sEngineName = 'SimpleCrypt' . $sEngineName . 'Engine';
return $sEngineName::GetNewDefaultParams();
}
/**
* Constructor
* @param string $sEngineName Engine for encryption. Values: Simple, Mcrypt, Sodium or OpenSSL
* @throws Exception This library is unkown
*/
function __construct($sEngineName = 'Mcrypt')
{
switch($sEngineName){
case 'Sodium':
if(!function_exists('sodium_crypto_secretbox_open')){
$sEngineName = 'Simple';
}
break;
case 'Mcrypt':
if(!function_exists('mcrypt_module_open')){
if (function_exists('openssl_decrypt'))
{
$sEngineName = 'OpenSSLMcryptCompatibility';
}
else
{
$sEngineName = 'Simple';
}
}
break;
case 'OpenSSL':
case 'OpenSSLMcryptCompatibility':
if(!function_exists('openssl_decrypt')){
$sEngineName = 'Simple';
}
break;
case 'Simple':
break;
default:
throw new Exception(Dict::Format("Core:AttributeEncryptUnknownLibrary", $sEngineName));
}
$sEngineName = 'SimpleCrypt' . $sEngineName . 'Engine';
$this->oEngine = new $sEngineName;
}
/**
* Encrypts the string with the given key
* @param string $key
* @param string $sString Plaintext string
* @return string Ciphered string
*/
function Encrypt($key, $sString)
{
return $this->oEngine->Encrypt($key,$sString);
}
/**
* Decrypts the string by the given key
* @param string $key
* @param string $string Ciphered string
* @return string Plaintext string
*/
function Decrypt($key, $string)
{
return $this->oEngine->Decrypt($key,$string);
}
/**
* Returns a random "salt" value, to be used when "hashing" a password
* using a one-way encryption algorithm, to prevent an attack using a "rainbow table"
* Tryes to use the best available random number generator
* @return string The generated random "salt"
*/
static function GetNewSalt()
{
// Copied from http://www.php.net/manual/en/function.mt-rand.php#83655
// get 128 pseudorandom bits in a string of 16 bytes
$sRandomBits = null;
// Unix/Linux platform?
$fp = @fopen('/dev/urandom','rb');
if ($fp !== FALSE)
{
//echo "Random bits pulled from /dev/urandom<br/>\n";
$sRandomBits .= @fread($fp,16);
@fclose($fp);
}
else
{
// MS-Windows platform?
if (@class_exists('COM'))
{
// http://msdn.microsoft.com/en-us/library/aa388176(VS.85).aspx
try
{
$CAPI_Util = new COM('CAPICOM.Utilities.1');
$sBase64RandomBits = ''.$CAPI_Util->GetRandom(16,0);
// if we ask for binary data PHP munges it, so we
// request base64 return value. We squeeze out the
// redundancy and useless ==CRLF by hashing...
if ($sBase64RandomBits)
{
//echo "Random bits got from CAPICOM.Utilities.1<br/>\n";
$sRandomBits = md5($sBase64RandomBits, TRUE);
}
}
catch (Exception $ex)
{
// echo 'Exception: ' . $ex->getMessage();
}
}
}
if ($sRandomBits == null)
{
// No "strong" random generator available, use PHP's built-in mechanism
//echo "Random bits generated from mt_rand<br/>\n";
mt_srand(crc32(microtime()));
$sRandomBits = '';
for($i = 0; $i < 4; $i++)
{
$sRandomBits .= sprintf('%04x', mt_rand(0, 65535));
}
}
return $sRandomBits;
}
}
/**
* Interface for encryption engines
*/
interface CryptEngine
{
public static function GetNewDefaultParams();
function Encrypt($key, $sString);
function Decrypt($key, $encrypted_data);
}
/**
* Simple Engine doesn't need any PHP extension.
* Every encryption of the same string with the same key
* will return the same encrypted string
*/
class SimpleCryptSimpleEngine implements CryptEngine
{
public static function GetNewDefaultParams()
{
return array( 'lib' => 'Simple', 'key' => null);
}
public function Encrypt($key, $sString)
{
$result = '';
for($i=1; $i<=strlen($sString); $i++)
{
$char = substr($sString, $i-1, 1);
$keychar = substr($key, ($i % strlen($key))-1, 1);
$char = chr(ord($char)+ord($keychar));
$result.=$char;
}
return $result;
}
public function Decrypt($key, $encrypted_data)
{
$result = '';
for($i=1; $i<=strlen($encrypted_data); $i++)
{
$char = substr($encrypted_data, $i-1, 1);
$keychar = substr($key, ($i % strlen($key))-1, 1);
$char = chr(ord($char)-ord($keychar));
$result.=$char;
}
return $result;
}
}
/**
* McryptEngine requires Mcrypt extension
* Every encryption of the same string with the same key
* will return a different encrypted string.
*/
class SimpleCryptMcryptEngine implements CryptEngine
{
var $alg = MCRYPT_BLOWFISH;
var $td = null;
public static function GetNewDefaultParams()
{
return array('lib' => 'Mcrypt', 'key' => null);
}
public function __construct()
{
$this->td = mcrypt_module_open($this->alg,'','cbc','');
}
public function Encrypt($key, $sString)
{
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($this->td), MCRYPT_DEV_URANDOM); // MCRYPT_DEV_URANDOM is now useable since itop requires php >= 5.6
if (false === $iv) {
throw new Exception('IV generation failed');
}
mcrypt_generic_init($this->td, $key, $iv);
if (empty($sString))
{
$sString = str_repeat("\0", 8);
}
$encrypted_data = mcrypt_generic($this->td, $sString);
mcrypt_generic_deinit($this->td);
return $iv.$encrypted_data;
}
public function Decrypt($key, $encrypted_data)
{
$iv = substr($encrypted_data, 0, mcrypt_enc_get_iv_size($this->td));
$string = substr($encrypted_data, mcrypt_enc_get_iv_size($this->td));
$r = mcrypt_generic_init($this->td, $key, $iv);
if (($r < 0) || ($r === false))
{
$decrypted_data = Dict::S("Core:AttributeEncryptFailedToDecrypt");
}
else
{
$decrypted_data = rtrim(mdecrypt_generic($this->td, $string), "\0");
mcrypt_generic_deinit($this->td);
}
return $decrypted_data;
}
public function __destruct()
{
mcrypt_module_close($this->td);
}
}
/**
* SodiumEngine requires Sodium extension
* Every encryption of the same string with the same key
* will return a different encrypted string.
* The key has to be SODIUM_CRYPTO_SECRETBOX_KEYBYTES bytes long.
*/
class SimpleCryptSodiumEngine implements CryptEngine
{
public static function GetNewDefaultParams()
{
return array('lib' => 'Sodium', 'key' => bin2hex(sodium_crypto_secretbox_keygen()));
}
public function Encrypt($key, $sString)
{
$key = hex2bin($key);
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$encrypted_string = sodium_crypto_secretbox($sString, $nonce, $key);
sodium_memzero($sString);
sodium_memzero($key);
return base64_encode($nonce.$encrypted_string);
}
public function Decrypt($key, $encrypted_data)
{
$key = hex2bin($key);
$encrypted_data = base64_decode($encrypted_data);
$nonce = mb_substr($encrypted_data, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
$encrypted_data = mb_substr($encrypted_data, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
$plaintext = sodium_crypto_secretbox_open($encrypted_data, $nonce, $key);
if ($plaintext === false)
{
$plaintext = Dict::S("Core:AttributeEncryptFailedToDecrypt");
}
sodium_memzero($encrypted_data);
sodium_memzero($key);
return $plaintext;
}
}
class SimpleCryptOpenSSLEngine implements CryptEngine
{
public static function GetNewDefaultParams()
{
return array('lib' => 'OpenSSL', 'key' => bin2hex(openssl_random_pseudo_bytes(32)));
}
public function Encrypt($key, $sString)
{
$key = hex2bin($key);
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length("AES-256-CBC"));
$encrypted_string = openssl_encrypt($sString, "AES-256-CBC", $key, 0 , $iv);
return $iv.$encrypted_string;
}
public function Decrypt($key, $encrypted_data)
{
$key = hex2bin($key);
$iv = mb_substr($encrypted_data, 0, openssl_cipher_iv_length("AES-256-CBC"), '8bit');
$encrypted_data = mb_substr($encrypted_data, openssl_cipher_iv_length("AES-256-CBC"), null, '8bit');
$plaintext = openssl_decrypt($encrypted_data,"AES-256-CBC", $key, 0 , $iv);
if ($plaintext === false)
{
$plaintext = Dict::S("Core:AttributeEncryptFailedToDecrypt");
}
return trim($plaintext);
}
}
class SimpleCryptOpenSSLMcryptCompatibilityEngine implements CryptEngine
{
public static function GetNewDefaultParams()
{
return array('lib' => 'OpenSSLMcryptCompatibility', 'key' => null);
}
//fix for php < 7.1.8 (keys are Zero padded instead of cycle padded)
static private function MakeOpenSSLBlowfishKey($key)
{
if("$key" === '')
{
return $key;
}
$len = (16+2)*4;
while(strlen($key) < $len)
{
$key .= $key;
}
$key = substr($key, 0, $len);
return $key;
}
public function Encrypt($key, $sString)
{
$key = SimpleCryptOpenSSLMcryptCompatibilityEngine::MakeOpenSSLBlowfishKey($key);
$blockSize = 8;
$len = strlen($sString);
$paddingLen = intval (($len + $blockSize -1) / $blockSize) * $blockSize - $len;
$padding = str_repeat("\0", $paddingLen);
$sData = $sString . $padding;
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length("BF-CBC"));
$encrypted_string = openssl_encrypt($sData, "BF-CBC", $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
return $iv.$encrypted_string;
}
public function Decrypt($key, $encrypted_data)
{
$key = SimpleCryptOpenSSLMcryptCompatibilityEngine::MakeOpenSSLBlowfishKey($key);
$iv = mb_substr($encrypted_data, 0, openssl_cipher_iv_length("BF-CBC"), '8bit');
$encrypted_data = mb_substr($encrypted_data, openssl_cipher_iv_length("BF-CBC"), null, '8bit');
$plaintext = openssl_decrypt($encrypted_data,"BF-CBC", $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
if ($plaintext === false)
{
$plaintext = Dict::S("Core:AttributeEncryptFailedToDecrypt");
}
return trim($plaintext);
}
}

View File

@@ -1,894 +0,0 @@
<?php
/**
* Copyright (C) 2013-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
*/
use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
/**
* A user defined trigger, to customize the application
* A trigger will activate an action
*
* @package iTopORM
*/
abstract class Trigger extends cmdbAbstractObject
{
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-conflict.svg'),
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("action_list",
array("linked_class" => "lnkTriggerAction", "ext_key_to_me" => "trigger_id", "ext_key_to_remote" => "action_id", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array())));
$aTags = ContextTag::GetTags();
MetaModel::Init_AddAttribute(new AttributeEnumSet("context", array("allowed_values" => null, "possible_values" => new ValueSetEnumPadded($aTags, true), "sql" => "context", "depends_on" => array(), "is_null_allowed" => true, "max_items" => 12)));
// "complement" is a computed field, fed by Trigger sub-classes, in general in ComputeValues method, for eg. the TriggerOnObject fed it with target_class info
MetaModel::Init_AddAttribute(new AttributeString("complement", array("allowed_values" => null, "sql" => "complement", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeEnum("subscription_policy", array("allowed_values" => new ValueSetEnum(Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::cases()), "sql" => "subscription_policy", "default_value" => \Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::AllowNoChannel->value, "is_null_allowed" => false, "depends_on" => array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('finalclass', 'description', 'context', 'subscription_policy', 'action_list', 'complement')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'complement')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
/**
* Check if the trigger can be used in the current context
*
* @return bool true if context OK
* @throws \ArchivedObjectException
* @throws \CoreException
*/
public function IsContextValid()
{
// Check the context
$oContext = $this->Get('context');
$bChecked = false;
$bValid = false;
foreach ($oContext->GetValues() as $sValue)
{
$bChecked = true;
if (ContextTag::Check($sValue))
{
$bValid = true;
break;
}
}
if ($bChecked && !$bValid)
{
// Trigger does not match the current context
return false;
}
return true;
}
/**
* @param $aContextArgs
*
* @throws \ArchivedObjectException
* @throws \CoreException
*/
public function DoActivate($aContextArgs)
{
// Check the context
if (!$this->IsContextValid())
{
// Trigger does not match the current context
$sClass = get_class($this);
$sName = $this->Get('friendlyname');
IssueLog::Debug("Context NOT valid for : {$sClass} '$sName'");
return;
}
$aContextArgs['trigger->object()'] = $this;
// Find the related actions
$oLinkedActions = $this->Get('action_list');
// Order actions as expected
$aActionListOrdered = [];
while ($oLink = $oLinkedActions->Fetch()) {
$aActionListOrdered[(int) $oLink->Get('order')][] = $oLink;
}
ksort($aActionListOrdered);
// Execute actions
foreach ($aActionListOrdered as $aActionSubList) {
foreach ($aActionSubList as $oLink) /** @var \DBObject $oLink */ {
/** @var \DBObject $oLink */
$iActionId = $oLink->Get('action_id');
/** @var \Action $oAction */
$oAction = MetaModel::GetObject('Action', $iActionId);
if ($oAction->IsActive()) {
$oKPI = new ExecutionKPI();
$aContextArgs['action->object()'] = $oAction;
$oAction->DoExecute($this, $aContextArgs);
$oKPI->ComputeStatsForExtension($oAction, 'DoExecute');
}
}
}
}
/**
* Check whether the given object is in the scope of this trigger
* and can potentially be the subject of notifications
*
* @param DBObject $oObject The object to check
*
* @return bool
*/
public function IsInScope(DBObject $oObject)
{
// By default the answer is no
// Overload this function in your own derived class for a different behavior
return false;
}
}
/**
* Class TriggerOnObject
*/
abstract class TriggerOnObject extends Trigger
{
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onobject",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeClass("target_class",
array("class_category" => "bizmodel", "more_values" => "User,UserExternal,UserInternal,UserLDAP,UserLocal", "sql" => "target_class", "default_value" => null, "is_null_allowed" => false, "depends_on" => array(), "class_exclusion_list" => "Attachment")));
MetaModel::Init_AddAttribute(new AttributeOQL("filter", array("allowed_values" => null, "sql" => "filter", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'description')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('default_search', array('description', 'target_class')); // Default criteria of the search banner
// MetaModel::Init_SetZListItems('standard_search', array('name', 'target_class', 'description')); // Criteria of the search form
}
/**
* @throws \CoreException
*/
public function DoCheckToWrite()
{
parent::DoCheckToWrite();
$sFilter = trim($this->Get('filter') ?? '');
if (strlen($sFilter) > 0)
{
try
{
$oSearch = DBObjectSearch::FromOQL($sFilter);
if (!MetaModel::IsParentClass($this->Get('target_class'), $oSearch->GetClass()))
{
$this->m_aCheckIssues[] = Dict::Format('TriggerOnObject:WrongFilterClass', $this->Get('target_class'));
}
} catch (OqlException $e)
{
$this->m_aCheckIssues[] = Dict::Format('TriggerOnObject:WrongFilterQuery', $e->getMessage());
}
}
}
/**
* @throws \CoreException
*/
public function ComputeValues()
{
parent::ComputeValues();
// Complementary name of a Trigger is manually built
// - the Trigger finalclass code not translated
// - an hardcoded text in english
// - the target class code not translated for TriggerOnObject subclasses
$this->Set('complement', 'class restriction: '.$this->Get('target_class'));
}
/**
* Check whether the given object is in the scope of this trigger
* and can potentially be the subject of notifications
*
* @param DBObject $oObject The object to check
*
* @return bool
* @throws \CoreException
*/
public function IsInScope(DBObject $oObject)
{
$sRootClass = $this->Get('target_class');
return ($oObject instanceof $sRootClass);
}
/**
* @param $aContextArgs
*
* @throws \ArchivedObjectException
* @throws \CoreException
*/
public function DoActivate($aContextArgs)
{
$bGo = true;
if (isset($aContextArgs['this->object()']))
{
/** @var \DBObject $oObject */
$oObject = $aContextArgs['this->object()'];
$bGo = $this->IsTargetObject($oObject->GetKey(), $oObject->ListPreviousValuesForUpdatedAttributes());
}
if ($bGo)
{
parent::DoActivate($aContextArgs);
}
}
/**
* if the target class is Attachment, then the trigger is read-only
* @param $sAttCode
* @param $aReasons
* @param $sTargetState
* @return int
* @throws ArchivedObjectException
* @throws CoreException
*/
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState='')
{
// Force the computed field to be read-only, preventing it to be written
if ($this->Get('target_class') == 'Attachment' ) {
return OPT_ATT_READONLY;
}
return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
}
public function DisplayBareHeader(WebPage $oPage, $bEditMode = false)
{
$aHeaderBlocks = parent::DisplayBareHeader($oPage, $bEditMode);
if ($this->Get('target_class') == 'Attachment' ) {
$oPage->AddUiBlock(AlertUIBlockFactory::MakeForWarning('', Dict::S('Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage')));
$oPage->add_ready_script("$('#UIMenuModify').hide();");
}
return $aHeaderBlocks;
}
/**
* Activate trigger based on attribute list given instead of changed attributes
*
* @param array $aContextArgs
* @param array|null $aAttributes if null default to changed attributes
*
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @since 3.1.1 3.2.0 N°6228
*/
public function DoActivateForSpecificAttributes(array $aContextArgs, ?array $aAttributes)
{
if (isset($aContextArgs['this->object()']))
{
/** @var \DBObject $oObject */
$oObject = $aContextArgs['this->object()'];
if (is_null($aAttributes)) {
$aChanges = $oObject->ListPreviousValuesForUpdatedAttributes();
} else {
$aChanges = array_fill_keys($aAttributes, true);
}
if (false === $this->IsTargetObject($oObject->GetKey(), $aChanges)) {
return;
}
}
parent::DoActivate($aContextArgs);
}
/**
* @param $iObjectId
* @param array $aChanges
*
* @return bool True if the object of ID $iObjectId is within the scope of the OQL defined by the "filter" attribute
*
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
public function IsTargetObject($iObjectId, $aChanges = array())
{
$sFilter = trim($this->Get('filter') ?? '');
if (strlen($sFilter) > 0) {
$oSearch = DBObjectSearch::FromOQL($sFilter);
$oSearch->AddCondition('id', $iObjectId, '=');
$oSearch->AllowAllData();
$oSet = new DBObjectSet($oSearch);
$bRet = ($oSet->Count() > 0);
} else {
$bRet = true;
}
return $bRet;
}
/**
* @param Exception $oException
* @param \DBObject $oObject
*
* @return void
*
* @uses \IssueLog::Error()
*
* @since 2.7.9 3.0.3 3.1.0 N°5893
*/
public function LogException($oException, $oObject)
{
$sObjectKey = $oObject->GetKey(); // if object wasn't persisted yet, then we'll have a negative value
$aContext = [
'exception.class' => get_class($oException),
'exception.message' => $oException->getMessage(),
'trigger.class' => get_class($this),
'trigger.id' => $this->GetKey(),
'trigger.friendlyname' => $this->GetRawName(),
'object.class' => get_class($oObject),
'object.id' => $sObjectKey,
'object.friendlyname' => $oObject->GetRawName(),
'current_user' => UserRights::GetUser(),
'exception.stack' => $oException->getTraceAsString(),
];
IssueLog::Error('A trigger did throw an exception', null, $aContext);
}
}
/**
* To trigger notifications when a ticket is updated from the portal
*/
class TriggerOnPortalUpdate extends TriggerOnObject
{
/**
* @throws \CoreException
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onportalupdate",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'description')); // Attributes to be displayed for a list
// Search criteria
}
}
/**
* Class TriggerOnStateChange
*/
abstract class TriggerOnStateChange extends TriggerOnObject
{
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onstatechange",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeClassState("state", array("class_field" => 'target_class', "allowed_values" => null, "sql" => "state", "default_value" => null, "is_null_allowed" => false, "depends_on" => array('target_class'))));
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'state')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
/**
* Class TriggerOnStateEnter
*/
class TriggerOnStateEnter extends TriggerOnStateChange
{
/**
* @throws \CoreException
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onstateenter",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
/**
* Class TriggerOnStateLeave
*/
class TriggerOnStateLeave extends TriggerOnStateChange
{
/**
* @throws \CoreException
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onstateleave",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('')); // Criteria of the advanced search form
}
}
/**
* Class TriggerOnObjectCreate
*/
class TriggerOnObjectCreate extends TriggerOnObject
{
/**
* @throws \CoreException
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onobjcreate",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
/**
* Class TriggerOnObjectCreate
*/
class TriggerOnObjectDelete extends TriggerOnObject
{
/**
* @throws \CoreException
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onobjdelete",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
/**
* Class TriggerOnObjectCreate
*/
class TriggerOnObjectUpdate extends TriggerOnObject
{
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onobjupdate",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeClassAttCodeSet('target_attcodes', array("allowed_values" => null, "class_field" => "target_class", "sql" => "target_attcodes", "default_value" => null, "is_null_allowed" => true, "max_items" => 20, "min_items" => 0, "attribute_definition_exclusion_list" => "AttributeDashboard,AttributeExternalField,AttributeFinalClass,AttributeFriendlyName,AttributeObsolescenceDate,AttributeObsolescenceFlag,AttributeSubItem", "attribute_definition_list" => null, "depends_on" => array('target_class'))));
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'target_attcodes', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
}
public function IsTargetObject($iObjectId, $aChanges = array())
{
if (!parent::IsTargetObject($iObjectId, $aChanges))
{
return false;
}
// Check the attribute
$oAttCodeSet = $this->Get('target_attcodes');
$aAttCodes = $oAttCodeSet->GetValues();
if (empty($aAttCodes))
{
return true;
}
foreach($aAttCodes as $sAttCode)
{
if (array_key_exists($sAttCode, $aChanges))
{
return true;
}
}
return false;
}
public function ComputeValues()
{
parent::ComputeValues();
// Remove unwanted attribute codes
$aChanges = $this->ListChanges();
if (isset($aChanges['target_attcodes']))
{
$oAttDef = MetaModel::GetAttributeDef(get_class($this), 'target_attcodes');
$aArgs = array('this' => $this);
$aAllowedValues = $oAttDef->GetAllowedValues($aArgs);
/** @var \ormSet $oValue */
$oValue = $this->Get('target_attcodes');
$aValues = $oValue->GetValues();
$bChanged = false;
foreach($aValues as $key => $sValue)
{
if (!isset($aAllowedValues[$sValue]))
{
unset($aValues[$key]);
$bChanged = true;
}
}
if ($bChanged)
{
$oValue->SetValues($aValues);
$this->Set('target_attcodes', $oValue);
}
}
}
}
/**
* Class TriggerOnObjectMention
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 3.0.0
*/
class TriggerOnObjectMention extends TriggerOnObject
{
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onobjmention",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeOQL("mentioned_filter", array("allowed_values" => null, "sql" => "mentioned_filter", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'mentioned_filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
}
/**
* @param \DBObject $oObject
*
* @return bool True if $oObject is within the scope of the OQL defined by the "mentioned_filter" attribute OR if no mentioned_filter defined. Otherwise, returns false.
*
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
public function IsMentionedObjectInScope(DBObject $oObject)
{
$sFilter = trim($this->Get('mentioned_filter'));
if (strlen($sFilter) > 0)
{
$oSearch = DBObjectSearch::FromOQL($sFilter);
$sSearchClass = $oSearch->GetClass();
// If filter not on current object class (or descendants), consider it as not in scope
if (is_a($oObject, $sSearchClass, true) === false) {
return false;
}
$oSearch->AddCondition('id', $oObject->GetKey(), '=');
if (MetaModel::IsAbstract($oSearch->GetClass())) {
$oSearch->AddCondition('finalclass', get_class($oObject), '=');
}
$aParams = $oObject->ToArgs('this');
$oSet = new DBObjectSet($oSearch, [], $aParams);
$bRet = $oSet->CountExceeds(0);
}
else
{
$bRet = true;
}
return $bRet;
}
}
/**
* Class TriggerOnAttributeBlobDownload
*
* @since 3.1.0
*/
class TriggerOnAttributeBlobDownload extends TriggerOnObject
{
/**
* @inheritDoc
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onattblobdownload",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
}
}
/**
* Class lnkTriggerAction
*/
class lnkTriggerAction extends cmdbAbstractObject
{
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array('action_id', 'trigger_id'),
"db_table" => "priv_link_action_trigger",
"db_key_field" => "link_id",
"db_finalclass_field" => "",
"is_link" => true,
'uniqueness_rules' => array(
'no_duplicate' => array(
'attributes' => array(
0 => 'action_id',
1 => 'trigger_id',
),
'filter' => '',
'disabled' => false,
'is_blocking' => true,
),
),
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", array("targetclass" => "Action", "jointype" => '', "allowed_values" => null, "sql" => "action_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("action_name", array("allowed_values" => null, "extkey_attcode" => 'action_id', "target_attcode" => "name")));
MetaModel::Init_AddAttribute(new AttributeExternalKey("trigger_id", array("targetclass" => "Trigger", "jointype" => '', "allowed_values" => null, "sql" => "trigger_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("trigger_name", array("allowed_values" => null, "extkey_attcode" => 'trigger_id', "target_attcode" => "description")));
MetaModel::Init_AddAttribute(new AttributeInteger("order", array("allowed_values" => null, "sql" => "order", "default_value" => 0, "is_null_allowed" => true, "depends_on" => array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('action_id', 'trigger_id', 'order')); // Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', array('action_id', 'trigger_id', 'order')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('action_id', 'trigger_id', 'order')); // Criteria of the std search form
MetaModel::Init_SetZListItems('advanced_search', array('action_id', 'trigger_id', 'order')); // Criteria of the advanced search form
}
}
/**
* Class TriggerOnThresholdReached
*/
class TriggerOnThresholdReached extends TriggerOnObject
{
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_threshold",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeClassAttCodeSet('stop_watch_code', array("allowed_values" => null, "class_field" => "target_class", "sql" => "stop_watch_code", "default_value" => null, "is_null_allowed" => false, "max_items" => 1, "min_items" => 1, "attribute_definition_exclusion_list" => null, "attribute_definition_list" => "AttributeStopWatch", "include_child_classes_attributes" => true, "depends_on" => array('target_class'))));
MetaModel::Init_AddAttribute(new AttributeString("threshold_index", array("allowed_values" => null, "sql" => "threshold_index", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'stop_watch_code', 'threshold_index', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('target_class', 'threshold_index', 'threshold_index')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}

View File

@@ -1,652 +0,0 @@
<?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/>
/**
* Value set definitions (from a fixed list or from a query, etc.)
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Core\MetaModel\FriendlyNameType;
require_once('MyHelpers.class.inc.php');
/**
* ValueSetDefinition
* value sets API and implementations
*
* @package iTopORM
*/
abstract class ValueSetDefinition
{
protected $m_bIsLoaded = false;
protected $m_aValues = array();
// Displayable description that could be computed out of the std usage context
public function GetValuesDescription()
{
$aValues = $this->GetValues(array(), '');
$aDisplayedValues = array();
foreach($aValues as $key => $value)
{
$aDisplayedValues[] = "$key => $value";
}
$sAllowedValues = implode(', ', $aDisplayedValues);
return $sAllowedValues;
}
/**
* @param array $aArgs
* @param string $sContains
* @param string $sOperation for the values {@see static::LoadValues()}
*
* @return array hash array of keys => values
*/
public function GetValues($aArgs, $sContains = '', $sOperation = 'contains')
{
if (!$this->m_bIsLoaded)
{
$this->LoadValues($aArgs);
$this->m_bIsLoaded = true;
}
if (strlen($sContains) == 0)
{
// No filtering
$aRet = $this->m_aValues;
}
else
{
// Filter on results containing the needle <sContain>
$aRet = array();
foreach ($this->m_aValues as $sKey=>$sValue)
{
if (stripos($sValue, $sContains) !== false)
{
$aRet[$sKey] = $sValue;
}
}
}
$this->SortValues($aRet);
return $aRet;
}
/**
* @param array $aValues Values to sort in the form keys => values
*
* @return void
* @since 3.1.0 N°1646 Create method
*/
public function SortValues(array &$aValues): void
{
// Sort alphabetically on values
natcasesort($aValues);
}
abstract protected function LoadValues($aArgs);
}
/**
* Set of existing values for an attribute, given a search filter
*
* @package iTopORM
*/
class ValueSetObjects extends ValueSetDefinition
{
protected $m_sContains;
protected $m_sOperation;
protected $m_sFilterExpr; // in OQL
protected $m_sValueAttCode;
protected $m_aOrderBy;
protected $m_oExtraCondition;
private $m_bAllowAllData;
private $m_aModifierProperties;
private $m_bSort;
private $m_iLimit;
/**
* @param hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending
*/
public function __construct($sFilterExp, $sValueAttCode = '', $aOrderBy = array(), $bAllowAllData = false, $aModifierProperties = array())
{
$this->m_sContains = '';
$this->m_sOperation = '';
$this->m_sFilterExpr = $sFilterExp;
$this->m_sValueAttCode = $sValueAttCode;
$this->m_aOrderBy = $aOrderBy;
$this->m_bAllowAllData = $bAllowAllData;
$this->m_aModifierProperties = $aModifierProperties;
$this->m_oExtraCondition = null;
$this->m_bSort = true;
$this->m_iLimit = 0;
}
public function SetModifierProperty($sPluginClass, $sProperty, $value)
{
$this->m_aModifierProperties[$sPluginClass][$sProperty] = $value;
$this->m_bIsLoaded = false;
}
public function SetCondition(DBSearch $oFilter)
{
$this->m_oExtraCondition = $oFilter;
$this->m_bIsLoaded = false;
}
public function SetOrderBy(array $aOrderBy)
{
$this->m_aOrderBy = $aOrderBy;
}
public function ToObjectSet($aArgs = array(), $sContains = '', $iAdditionalValue = null)
{
if ($this->m_bAllowAllData)
{
$oFilter = DBObjectSearch::FromOQL_AllData($this->m_sFilterExpr);
}
else
{
$oFilter = DBObjectSearch::FromOQL($this->m_sFilterExpr);
}
if (!is_null($this->m_oExtraCondition))
{
$oFilter = $oFilter->Intersect($this->m_oExtraCondition);
}
foreach($this->m_aModifierProperties as $sPluginClass => $aProperties)
{
foreach ($aProperties as $sProperty => $value)
{
$oFilter->SetModifierProperty($sPluginClass, $sProperty, $value);
}
}
if ($iAdditionalValue > 0)
{
$oSearchAdditionalValue = new DBObjectSearch($oFilter->GetClass());
$oSearchAdditionalValue->AddConditionExpression( new BinaryExpression(
new FieldExpression('id', $oSearchAdditionalValue->GetClassAlias()),
'=',
new VariableExpression('current_extkey_id'))
);
$oSearchAdditionalValue->AllowAllData();
$oSearchAdditionalValue->SetArchiveMode(true);
$oSearchAdditionalValue->SetInternalParams( array('current_extkey_id' => $iAdditionalValue) );
$oFilter = new DBUnionSearch(array($oFilter, $oSearchAdditionalValue));
}
return new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs);
}
/**
* @inheritDoc
* @throws CoreException
* @throws OQLException
*/
public function GetValues($aArgs, $sContains = '', $sOperation = 'contains')
{
if (!$this->m_bIsLoaded || ($sContains != $this->m_sContains) || ($sOperation != $this->m_sOperation))
{
$this->LoadValues($aArgs, $sContains, $sOperation);
$this->m_bIsLoaded = true;
}
// The results are already filtered and sorted (on friendly name)
$aRet = $this->m_aValues;
return $aRet;
}
/**
* @param $aArgs
* @param string $sContains
* @param string $sOperation 'contains' or 'equals_start_with'
*
* @return bool
* @throws \CoreException
* @throws \OQLException
*/
protected function LoadValues($aArgs, $sContains = '', $sOperation = 'contains')
{
$this->m_sContains = $sContains;
$this->m_sOperation = $sOperation;
$this->m_aValues = array();
$oFilter = $this->GetFilter($sOperation, $sContains);
$oObjects = new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs, null, $this->m_iLimit, 0, $this->m_bSort);
if (empty($this->m_sValueAttCode)) {
$aAttToLoad = array($oFilter->GetClassAlias() => array('friendlyname'));
} else {
$aAttToLoad = array($oFilter->GetClassAlias() => array($this->m_sValueAttCode));
}
$oObjects->OptimizeColumnLoad($aAttToLoad);
while ($oObject = $oObjects->Fetch()) {
if (empty($this->m_sValueAttCode)) {
$this->m_aValues[$oObject->GetKey()] = $oObject->GetName();
} else {
$this->m_aValues[$oObject->GetKey()] = $oObject->Get($this->m_sValueAttCode);
}
}
return true;
}
/**
* Get filter for functions LoadValues and LoadValuesForAutocomplete
*
* @param $sOperation
* @param $sContains
*
* @return \DBObjectSearch|\DBSearch|\DBUnionSearch|false|mixed
* @throws \CoreException
* @throws \OQLException
* @since 3.0.3 3.1.0
*/
protected function GetFilter($sOperation, $sContains)
{
$this->m_sContains = $sContains;
$this->m_sOperation = $sOperation;
if ($this->m_bAllowAllData) {
$oFilter = DBObjectSearch::FromOQL_AllData($this->m_sFilterExpr);
} else {
$oFilter = DBObjectSearch::FromOQL($this->m_sFilterExpr);
$oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
}
if (!$oFilter) {
return false;
}
if (!is_null($this->m_oExtraCondition)) {
$oFilter = $oFilter->Intersect($this->m_oExtraCondition);
}
foreach ($this->m_aModifierProperties as $sPluginClass => $aProperties) {
foreach ($aProperties as $sProperty => $value) {
$oFilter->SetModifierProperty($sPluginClass, $sProperty, $value);
}
}
$sClass = $oFilter->GetClass();
switch ($this->m_sOperation) {
case 'equals':
case 'start_with':
if ($this->m_sOperation === 'start_with') {
$this->m_sContains .= '%';
$sOperator = 'LIKE';
} else {
$sOperator = '=';
}
$aAttributes = MetaModel::GetFriendlyNameAttributeCodeList($sClass);
if (count($aAttributes) > 0) {
$sClassAlias = $oFilter->GetClassAlias();
$aFilters = array();
$oValueExpr = new ScalarExpression($this->m_sContains);
foreach ($aAttributes as $sAttribute) {
$oNewFilter = $oFilter->DeepClone();
$oNameExpr = new FieldExpression($sAttribute, $sClassAlias);
$oCondition = new BinaryExpression($oNameExpr, $sOperator, $oValueExpr);
$oNewFilter->AddConditionExpression($oCondition);
$aFilters[] = $oNewFilter;
}
// Unions are much faster than OR conditions
$oFilter = new DBUnionSearch($aFilters);
} else {
$oValueExpr = new ScalarExpression($this->m_sContains);
$oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias());
$oNewCondition = new BinaryExpression($oNameExpr, $sOperator, $oValueExpr);
$oFilter->AddConditionExpression($oNewCondition);
}
break;
default:
$oValueExpr = new ScalarExpression('%'.$this->m_sContains.'%');
$oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias());
$oNewCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
$oFilter->AddConditionExpression($oNewCondition);
break;
}
return $oFilter;
}
public function GetValuesDescription()
{
return 'Filter: '.$this->m_sFilterExpr;
}
public function GetFilterExpression()
{
return $this->m_sFilterExpr;
}
/**
* @param $iLimit
*/
public function SetLimit($iLimit)
{
$this->m_iLimit = $iLimit;
}
/**
* @param $bSort
*/
public function SetSort($bSort)
{
$this->m_bSort = $bSort;
}
public function GetValuesForAutocomplete($aArgs, $sContains = '', $sOperation = 'contains')
{
if (!$this->m_bIsLoaded || ($sContains != $this->m_sContains) || ($sOperation != $this->m_sOperation))
{
$this->LoadValuesForAutocomplete($aArgs, $sContains, $sOperation);
$this->m_bIsLoaded = true;
}
// The results are already filtered and sorted (on friendly name)
$aRet = $this->m_aValues;
return $aRet;
}
/**
* @param $aArgs
* @param string $sContains
* @param string $sOperation 'contains' or 'equals_start_with'
*
* @return bool
* @throws \CoreException
* @throws \OQLException
*/
protected function LoadValuesForAutocomplete($aArgs, $sContains = '', $sOperation = 'contains')
{
$this->m_aValues = array();
$oFilter = $this->GetFilter($sOperation, $sContains);
$sClass = $oFilter->GetClass();
$sClassAlias = $oFilter->GetClassAlias();
$oObjects = new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs, null, $this->m_iLimit, 0, $this->m_bSort);
if (empty($this->m_sValueAttCode)) {
$aAttToLoad = ['friendlyname'];
} else {
$aAttToLoad = [$this->m_sValueAttCode];
}
$sImageAttr = MetaModel::GetImageAttributeCode($sClass);
if (!empty($sImageAttr)) {
$aAttToLoad [] = $sImageAttr;
}
$aComplementAttributeSpec = MetaModel::GetNameSpec($sClass, FriendlyNameType::COMPLEMENTARY);
$sFormatAdditionalField = $aComplementAttributeSpec[0];
$aAdditionalField = $aComplementAttributeSpec[1];
if (count($aAdditionalField) > 0) {
if (is_array($aAdditionalField)) {
$aAttToLoad = array_merge($aAttToLoad, $aAdditionalField);
} else {
$aAttToLoad [] = $aAdditionalField;
}
}
$oObjects->OptimizeColumnLoad([$sClassAlias => $aAttToLoad]);
while ($oObject = $oObjects->Fetch()) {
$aData = [];
if (empty($this->m_sValueAttCode)) {
$aData['label'] = $oObject->GetName();
} else {
$aData['label'] = $oObject->Get($this->m_sValueAttCode);
}
if ($oObject->IsObsolete()) {
$aData['obsolescence_flag'] = '1';
} else {
$aData['obsolescence_flag'] = '0';
}
if (count($aAdditionalField) > 0) {
$aArguments = [];
foreach ($aAdditionalField as $sAdditionalField) {
array_push($aArguments, $oObject->Get($sAdditionalField));
}
$aData['additional_field'] = utils::VSprintf($sFormatAdditionalField, $aArguments);
} else {
$aData['additional_field'] = '';
}
if (!empty($sImageAttr)) {
/** @var \ormDocument $oImage */
$oImage = $oObject->Get($sImageAttr);
if (!$oImage->IsEmpty()) {
$aData['picture_url'] = $oImage->GetDisplayURL($sClass, $oObject->GetKey(), $sImageAttr);
$aData['initials'] = '';
} else {
$aData['initials'] = utils::ToAcronym($aData['label']);
}
}
$this->m_aValues[$oObject->GetKey()] = $aData;
}
return true;
}
}
/**
* Fixed set values (could be hardcoded in the business model)
*
* @package iTopORM
*/
class ValueSetEnum extends ValueSetDefinition
{
protected $m_values;
/**
* @var bool $bSortByValues If true, values will be sorted at runtime (on their values, not their keys), otherwise it is sorted at compile time in a predefined order.
* {@see \MFCompiler::CompileAttributeEnumValues()} for complete reasons.
* @since 3.1.0 N°1646
*/
protected bool $bSortByValues;
/**
* @param array|string $Values
* @param bool $bLocalizedSort
*
* @since 3.1.0 N°1646 Add $bLocalizedSort parameter
* @since 3.2.0 N°7157 $Values can be an array of backed-enum cases
*/
public function __construct($Values, bool $bSortByValues = false)
{
$this->m_values = $Values;
$this->bSortByValues = $bSortByValues;
}
/**
* @see \ValueSetEnum::$bSortByValues
* @return bool
* @since 3.1.0 N°1646
*/
public function IsSortedByValues(): bool
{
return $this->bSortByValues;
}
// Helper to export the data model
public function GetValueList()
{
$this->LoadValues(null);
return $this->m_aValues;
}
/**
* @inheritDoc
* @since 3.1.0 N°1646 Overload method
*/
public function SortValues(array &$aValues): void
{
// Force sort by values only if necessary
if ($this->bSortByValues) {
natcasesort($aValues);
return;
}
// Don't sort values as we rely on the order defined during compilation
return;
}
/**
* @param array|string $aArgs
*
* @return true
*/
protected function LoadValues($aArgs)
{
$aValues = [];
if (is_array($this->m_values))
{
foreach ($this->m_values as $key => $value) {
// Handle backed-enum case
if (is_object($value) && enum_exists(get_class($value))) {
$aValues[$value->value] = $value->value;
continue;
}
$aValues[$key] = $value;
}
}
elseif (is_string($this->m_values) && strlen($this->m_values) > 0)
{
foreach (explode(",", $this->m_values) as $sVal)
{
$sVal = trim($sVal);
$sKey = $sVal;
$aValues[$sKey] = $sVal;
}
}
else
{
$aValues = [];
}
$this->m_aValues = $aValues;
return true;
}
}
class ValueSetEnumPadded extends ValueSetEnum
{
/**
* @inheritDoc
* @since 3.1.0 N°6448 Add $bSortByValues parameter
*/
public function __construct($Values, bool $bSortByValues = false)
{
parent::__construct($Values, $bSortByValues);
if (is_string($Values))
{
$this->LoadValues(null);
}
else
{
$this->m_aValues = $Values;
}
$aPaddedValues = array();
foreach ($this->m_aValues as $sKey => $sVal)
{
// Pad keys to the min. length required by the \AttributeSet
$sKey = str_pad($sKey, 3, '_', STR_PAD_LEFT);
$aPaddedValues[$sKey] = $sVal;
}
$this->m_values = $aPaddedValues;
}
}
/**
* Fixed set values, defined as a range: 0..59 (with an optional increment)
*
* @package iTopORM
*/
class ValueSetRange extends ValueSetDefinition
{
protected $m_iStart;
protected $m_iEnd;
public function __construct($iStart, $iEnd, $iStep = 1)
{
$this->m_iStart = $iStart;
$this->m_iEnd = $iEnd;
$this->m_iStep = $iStep;
}
protected function LoadValues($aArgs)
{
$iValue = $this->m_iStart;
for($iValue = $this->m_iStart; $iValue <= $this->m_iEnd; $iValue += $this->m_iStep)
{
$this->m_aValues[$iValue] = $iValue;
}
return true;
}
}
/**
* Data model classes
*
* @package iTopORM
*/
class ValueSetEnumClasses extends ValueSetEnum
{
protected $m_sCategories;
public function __construct($sCategories = '', $sAdditionalValues = '')
{
$this->m_sCategories = $sCategories;
parent::__construct($sAdditionalValues, true /* Classes are always sorted alphabetically */);
}
protected function LoadValues($aArgs)
{
// Call the parent to parse the additional values...
parent::LoadValues($aArgs);
// Translate the labels of the additional values
foreach($this->m_aValues as $sClass => $void)
{
if (MetaModel::IsValidClass($sClass))
{
$this->m_aValues[$sClass] = MetaModel::GetName($sClass);
}
else
{
unset($this->m_aValues[$sClass]);
}
}
// Then, add the classes from the category definition
foreach (MetaModel::GetClasses($this->m_sCategories) as $sClass)
{
if (MetaModel::IsValidClass($sClass))
{
$this->m_aValues[$sClass] = MetaModel::GetName($sClass);
}
else
{
unset($this->m_aValues[$sClass]);
}
}
return true;
}
}

View File

@@ -39,23 +39,6 @@
//
// .site-nav a { color:#BADA55!important; }
$ibo-shame--switch--width: 36px !default;
$ibo-shame--switch--height: 20px !default;
$ibo-shame--slider--background-color: $ibo-color-secondary-600 !default;
$ibo-shame--slider--before--height: 15px !default;
$ibo-shame--slider--before--width: 15px !default;
$ibo-shame--slider--before--background-color: $ibo-color-secondary-300 !default;
$ibo-shame--slider--is-checked--background-color: $ibo-color-primary-600 !default;
$ibo-shame--slider--is-focus--box-shadow: 0 0 1px $ibo-color-primary-600 !default;
$ibo-shame--slider--is-round--border-radius: 20px !default;
$ibo-shame--slider--is-round--before--border-radius: 7px !default;
// N°2847 - Recolor svg illustrations with iTop's primary color
.ibo-svg-illustration--container > svg *[fill="#6c63ff"]{
fill: $ibo-svg-illustration--fill;
@@ -73,8 +56,8 @@ $ibo-shame--slider--is-round--before--border-radius: 7px !default;
.switch {
position: relative;
display: inline-block;
width: $ibo-shame--switch--width;
height: $ibo-shame--switch--height;
width: 36px;
height: 20px;
vertical-align: baseline;
}
@@ -91,27 +74,27 @@ $ibo-shame--slider--is-round--before--border-radius: 7px !default;
left: 0;
right: 0;
bottom: 0;
background-color: $ibo-shame--slider--background-color;
background-color: $ibo-color-secondary-600;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: $ibo-shame--slider--before--height;
width: $ibo-shame--slider--before--width;
height: 15px;
width: 15px;
left: 3px;
bottom: 3px;
background-color: $ibo-shame--slider--before--background-color;
background-color: $ibo-color-secondary-300;
transition: .4s;
}
input:checked + .slider {
background-color: $ibo-shame--slider--is-checked--background-color;
background-color: $ibo-color-primary-600;
}
input:focus + .slider {
box-shadow: $ibo-shame--slider--is-focus--box-shadow;
box-shadow: 0 0 1px $ibo-color-primary-600;
}
input:checked + .slider:before {
@@ -120,9 +103,9 @@ input:checked + .slider:before {
/* Rounded sliders */
.slider.round {
border-radius: $ibo-shame--slider--is-round--border-radius;
border-radius: 20px;
}
.slider.round:before {
border-radius: $ibo-shame--slider--is-round--before--border-radius;
border-radius: 7px;
}

View File

@@ -3,14 +3,12 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
$ibo-bulk--bulk-modify--incompatible-attribute--color--margin-right: $ibo-vendors-selectize--item--icon--margin-right !default;
$ibo-bulk--bulk-modify--incompatible-attribute--color: $ibo-color-information-500 !default;
.ibo-bulk--bulk-modify--incompatible-attribute {
&:before{
margin-right: $ibo-bulk--bulk-modify--incompatible-attribute--color--margin-right;
margin-right: $ibo-vendors-selectize--item--icon--margin-right;
@extend %fa-solid-base;
content: '\f05a';
color: $ibo-bulk--bulk-modify--incompatible-attribute--color;
color: $ibo-color-information-500;
}
}

View File

@@ -3,16 +3,12 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
$ibo-linked-set--bulk-tooltip-info--content: '\f05a' !default;
$ibo-linked-set--bulk-tooltip-info--color: $ibo-color-information-500 !default;
$ibo-linked-set--bulk-tooltip-info--margin-right: $ibo-vendors-selectize--item--icon--margin-right !default;
.ibo-linked-set--bulk-tooltip-info {
@extend %ibo-font-ral-nor-100;
font-size: $ibo-font-size-100;
&:before{
margin-right: $ibo-linked-set--bulk-tooltip-info--margin-right;
margin-right: $ibo-vendors-selectize--item--icon--margin-right;
@extend %fa-solid-base;
content: $ibo-linked-set--bulk-tooltip-info--content;
color: $ibo-linked-set--bulk-tooltip-info--color;
content: '\f05a';
color: $ibo-color-information-500;
}
}

View File

@@ -9,4 +9,8 @@
.ibo-details .ibo-prop--apply {
display: table-column;
}
.ibo-details {
margin-top: 5px;
}

View File

@@ -16,7 +16,7 @@
@import "panel/all";
@import "pill/all";
@import "dashlet/all";
@import "prop-within-details";
@import "add-to-dashboard";
@import "caselog-entry-form-within-activity-panel";
@import "tab-container-within-panel";
@import "medallion-with-blocklist";

View File

@@ -3,17 +3,13 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
$ibo-medallion-with-blocklist--icon--image--margin-x: auto !default;
$ibo-medallion-with-blocklist--icon--image--margin-y: 0 !default;
$ibo-medallion-with-blocklist--icon--description--margin-top: $ibo-spacing-400 !default;
.ibo-block-list--medallion{
flex-direction: column;
align-items: center;
> .ibo-medallion-icon--image{
margin: $ibo-medallion-with-blocklist--icon--image--margin-y $ibo-medallion-with-blocklist--icon--image--margin-x;
margin: 0 auto;
~ .ibo-medallion-icon--description{
margin-top: $ibo-medallion-with-blocklist--icon--description--margin-top;
margin-top: 12px;
}
}
> .ibo-medallion-icon--description{

View File

@@ -15,13 +15,6 @@ $ibo-panel-with-tab-container--margin-bottom: -1 * $ibo-panel--body--padding-bot
$ibo-panel-with-tab-container--tab-toggler--font-size--is-sticking: $ibo-font-size-100 !default;
$ibo-tab-container-within-panel--tabs-list--padding-top: $ibo-spacing-800 !default;
// I'm not sure where these values come from, might need to be replaced by variables
$ibo-tab-container-within-panel--tabs-list--min-width: calc(32px + 90px + 32px) !default;
$ibo-tab-container-within-panel--tabs-header--height: $ibo-spacing-800 !default;
$ibo-tab-container-within-panel--tabs--list--is-sticking--z-index: 10 !default;
$ibo-tab-container-within-panel--tabs--list--is-sticking--is-not-vertical--padding-left: $ibo-spacing-0 !default;
// Note: We use the child ">" selector to ensure this applies only to the child tab container, not another one that would be nested
.ibo-panel {
> .ibo-panel--body {
@@ -42,15 +35,15 @@ $ibo-tab-container-within-panel--tabs--list--is-sticking--is-not-vertical--paddi
flex-direction: row;
> .ibo-tab-container--tabs-list {
padding-top: $ibo-tab-container-within-panel--tabs-list--padding-top;
padding-top: 50px;
flex-direction: column;
height: auto;
padding-left: unset;
margin-right: unset;
min-width: $ibo-tab-container-within-panel--tabs-list--min-width;
min-width: calc(32px + 90px + 32px);
> .ibo-tab-container--tab-header {
height: $ibo-tab-container-within-panel--tabs-header--height;
height: 50px;
width: 100%;
justify-content: left;
@@ -75,12 +68,12 @@ $ibo-tab-container-within-panel--tabs--list--is-sticking--is-not-vertical--paddi
> .ibo-tab-container {
> .ibo-tab-container--tabs-list.ibo-is-sticking {
position: fixed;
z-index: $ibo-tab-container-within-panel--tabs--list--is-sticking--z-index;
z-index: 10;
}
&:not(.ibo-is-vertical){
> .ibo-tab-container--tabs-list.ibo-is-sticking {
padding-left: $ibo-tab-container-within-panel--tabs--list--is-sticking--is-not-vertical--padding-left;
padding-left: 0;
.ibo-tab-container--tab-toggler,
.ibo-tab-container--extra-tabs-list-toggler {

View File

@@ -3,11 +3,8 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
$ibo-datatable-within-panel--panel-body--width: 100% !default;
.ibo-panel .ibo-panel--body{
.ibo-datatable{
width: $ibo-datatable-within-panel--panel-body--width;
width: 100%
}
}

View File

@@ -3,8 +3,6 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
$ibo-object-details-with-tab-container--tab-list--padding-left: calc(#{$ibo-object-details--icon--spacing--as-medallion} + #{$ibo-object-details--icon--size} + #{$ibo-object-details--icon--spacing--as-medallion} - #{$ibo-tab-container--tab-toggler--padding-x}) !default;
// Note: We use the child ">" selector to ensure this applies only the child tab container, not another one that would be nested
.ibo-object-details.ibo-has-medallion-icon {
> .ibo-panel--body {
@@ -12,7 +10,7 @@ $ibo-object-details-with-tab-container--tab-list--padding-left: calc(#{$ibo-obje
> .ibo-tab-container:not(.ibo-is-vertical) {
> .ibo-tab-container--tabs-list {
// Align tab toggler's title with the panel's title
padding-left: $ibo-object-details-with-tab-container--tab-list--padding-left;
padding-left: calc(#{$ibo-object-details--icon--spacing--as-medallion} + #{$ibo-object-details--icon--size} + #{$ibo-object-details--icon--spacing--as-medallion} - #{$ibo-tab-container--tab-toggler--padding-x});
}
}
}

View File

@@ -9,12 +9,6 @@ $ibo-dashlet--width--is-inline: auto !default;
$ibo-dashlet--elements-spacing-x: $ibo-spacing-600 !default;
$ibo-dashlet--elements-spacing-y: $ibo-spacing-600 !default;
$ibo-dashlet-blocker--z-index: 9 !default; /* To be above calendar links & all, but below .close-box (9) */
$ibo-dashlet-blocker--top: 0 !default;
$ibo-dashlet-blocker--left: 0 !default;
$ibo-dashlet-blocker--width: 100% !default;
$ibo-dashlet-blocker--height: 100% !default;
/* Rules */
.ibo-dashlet {
position: relative;
@@ -29,13 +23,18 @@ $ibo-dashlet-blocker--height: 100% !default;
.ibo-dashlet--is-inline {
width: $ibo-dashlet--width--is-inline;
}
.ibo-details > .ibo-prop--apply {
display: table-column;
}
.ibo-details{
margin-top: 5px;
}
.ibo-dashlet-blocker{
position: absolute;
z-index: $ibo-dashlet-blocker--z-index;
top: $ibo-dashlet-blocker--top;
left: $ibo-dashlet-blocker--left;
width: $ibo-dashlet-blocker--width;
height: $ibo-dashlet-blocker--height;
z-index: 9; /* To be above calendar links & all, but below .close-box (9) */
top: 0;
left: 0;
width: 100%;
height: 100%;
cursor: not-allowed;
}

View File

@@ -24,8 +24,6 @@ $ibo-datatable--sort-order--color: $ibo-color-primary-600 !default;
$ibo-fieldsorter--selected--background-color: $ibo-color-blue-200 !default;
$ibo-datatable--selected-result-count--padding-right: 0.2em !default;
$ibo-datatable--selected-result-count--padding-left: 0.1em !default;
/* CSS variables (can be changed directly from the browser) */
:root {
@@ -136,8 +134,8 @@ $ibo-datatable--selected-result-count--padding-left: 0.1em !default;
}
.ibo-datatable--selected-count, .ibo-datatable--result-count{
padding-right: $ibo-datatable--selected-result-count--padding-right;
padding-left: $ibo-datatable--selected-result-count--padding-left;
padding-right: 0.2em;
padding-left: 0.1em;
}
//

View File

@@ -3,7 +3,7 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
$ibo-input-image--image-view--min-height: $ibo-size-500 !default;
$ibo-input-image--image-view--min-height: 96px !default;
$ibo-input-image--image-view--background-color: $ibo-color-grey-200 !default;
$ibo-input-image--image-view--border-radius: $ibo-border-radius-500 !default;

View File

@@ -1,14 +1,5 @@
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
$ibo-input-richtext-placeholder--height: $ibo-size-600 !default;
$ibo-input-richtext-placeholder--width: 100% !default;
.ibo-input-richtext-placeholder{
height: $ibo-input-richtext-placeholder--height;
width: $ibo-input-richtext-placeholder--width;
height: 200px;
width: 100%;
visibility: hidden;
}

View File

@@ -3,8 +3,6 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
$ibo-input-select-icon--menu--icon--max-height: 100% !default;
$ibo-input-select-icon--menu--icon--max-width: 100% !default;
$ibo-input-select-icon--icon--padding-right: $ibo-spacing-200 !default;
$ibo-input-select-icon--menu--z-index: 21 !default;
@@ -18,8 +16,8 @@ $ibo-input-select-icon--menu--icon--margin-right: 10px !default;
display: inline-flex;
text-align: left;
>img{
max-height: $ibo-input-select-icon--menu--icon--max-height;
max-width: $ibo-input-select-icon--menu--icon--max-width;
max-height: 100%;
max-width: 100%;
padding-right: $ibo-input-select-icon--icon--padding-right;
}
>span{

View File

@@ -20,7 +20,6 @@ $ibo-input-select-selectize--item--active--background-color: $ibo-color-blue-100
$ibo-input-select-wrapper--width: 100% !default;
$ibo-input-select-wrapper--after--content: "\f0d7" !default;
$ibo-input-select-wrapper--after--right: 8px !default;
$ibo-input-select-wrapper--after--height: 28px !default;
$ibo-input-select-wrapper--after--margin-left: -16px !default;
@@ -33,7 +32,6 @@ $ibo-input-select--action-button--height: 28px !default;
$ibo-input-select--action-button--width: 23px !default;
$ibo-input-select--action-button--margin-top: $ibo-spacing-0 !default;
$ibo-input-select--action-button--margin-right: 3px !default;
$ibo-input-select--action-button--font-size: $ibo-font-size-100 !default;
$ibo-input-select--action-button--background-color: inherit !default;
$ibo-input-select--action-button--color: $ibo-color-grey-800 !default;
$ibo-input-select--action-button--padding-x: $ibo-spacing-100 !default;
@@ -59,7 +57,7 @@ $ibo-input-select--autocomplete-item-image--border: 1px solid $ibo-color-grey-60
min-width: $ibo-input-select-selectize--value--min-midth !important;
input {
border-width: 0;
border-width: 0px;
color: inherit;
border-color: $ibo-color-white-100;
padding-left: $ibo-input-select--padding-x;
@@ -123,7 +121,7 @@ $ibo-input-select--autocomplete-item-image--border: 1px solid $ibo-color-grey-60
.ibo-input-select-wrapper::after{
position: absolute;
z-index: 1;
content: $ibo-input-select-wrapper--after--content;
content: "\f0d7";
font-family: "Font Awesome 5 Free";
font-weight: 600;
@@ -147,7 +145,7 @@ $ibo-input-select--autocomplete-item-image--border: 1px solid $ibo-color-grey-60
.ibo-input-select-wrapper--with-buttons:not(.ibo-input-select-autocomplete-wrapper)::after {
position: absolute;
z-index: 1;
content: $ibo-input-select-wrapper--after--content;
content: "\f0d7";
font-family: "Font Awesome 5 Free";
font-weight: 600;
cursor: pointer;
@@ -170,7 +168,7 @@ $ibo-input-select--autocomplete-item-image--border: 1px solid $ibo-color-grey-60
margin-top: $ibo-input-select--action-button--margin-top;
margin-right: $ibo-input-select--action-button--margin-right;
font-size: $ibo-input-select--action-button--font-size;
font-size: $ibo-font-size-100;
background-color: $ibo-input-select--action-button--background-color;
color: $ibo-input-select--action-button--color;
padding: $ibo-input-select--action-button--padding-y $ibo-input-select--action-button--padding-x;

View File

@@ -8,9 +8,6 @@ $ibo-input-text--min-height: 12rem !default;
$ibo-input-text--padding-x: $ibo-spacing-400 !default;
$ibo-input-text--padding-y: 10px !default;
$ibo-input-text--export--width: 100% !default;
$ibo-input-text--export--min-height: 15em !default;
.ibo-input-text {
width: $ibo-input-text--width;
min-height: $ibo-input-text--min-height;
@@ -26,6 +23,6 @@ $ibo-input-text--export--min-height: 15em !default;
}
.ibo-input-text--export {
width: $ibo-input-text--export--width;
min-height: $ibo-input-text--export--min-height;
width: 100%;
min-height: 15em;
}

View File

@@ -9,8 +9,6 @@ $ibo-toggler--wrapper--height: 20px !default;
$ibo-toggler--slider--border-radius: $ibo-border-radius-900 !default;
$ibo-toggler--slider--background-color: $ibo-color-secondary-600 !default;
$ibo-toggler--slider--before--left: 3px !default;
$ibo-toggler--slider--before--bottom: 3px !default;
$ibo-toggler--slider--before--height: 15px !default;
$ibo-toggler--slider--before--width: 15px !default;
$ibo-toggler--slider--before--border-radius: $ibo-border-radius-full !default;
@@ -48,8 +46,8 @@ $ibo-toggler--label--margin-left: 4px !default;
.ibo-toggler--slider:before {
content: "";
position: absolute;
left: $ibo-toggler--slider--before--left;
bottom: $ibo-toggler--slider--before--bottom;
left: 3px;
bottom: 3px;
height: $ibo-toggler--slider--before--height;
width: $ibo-toggler--slider--before--width;
border-radius: $ibo-toggler--slider--before--border-radius;

View File

@@ -27,9 +27,6 @@ $ibo-input--disabled--background-color: $ibo-color-grey-300 !default;
$ibo-input--placeholder--color: $ibo-color-grey-700 !default;
$ibo-input-wrapper--is-error--border-color: $ibo-color-red-600 !default;
$ibo-input-wrapper--vanilla--is-error--border: 0 !default;
$ibo-input-wrapper--vanilla--is-error--background-color: $ibo-color-transparent !default;
$ibo-field-validation: $ibo-color-red-700 !default;
$ibo-input--margin-x: $ibo-spacing-200 !default;
@@ -65,8 +62,8 @@ textarea.ibo-input{
border-color: $ibo-input-wrapper--is-error--border-color;
}
.ibo-input-vanilla input{
border: $ibo-input-wrapper--vanilla--is-error--border;
background-color: $ibo-input-wrapper--vanilla--is-error--background-color;
border: 0;
background-color: #11ffee00;
}
}
input.ibo-input-vanilla{

View File

@@ -10,10 +10,6 @@ $ibo-popover-menu--padding: $ibo-spacing-0 !default;
$ibo-popover-menu--toggler-visual-hint--margin-left: 0.5rem !default;
$ibo-popover-menu--section--height: 100% !default;
$ibo-popover-menu--section--margin-x: $ibo-spacing-0 !default;
$ibo-popover-menu--section--margin-y: $ibo-spacing-0 !default;
$ibo-popover-menu--section-border-radius: $ibo-popover-menu--border-radius !default;
.ibo-popover-menu {
@@ -39,8 +35,8 @@ $ibo-popover-menu--section-border-radius: $ibo-popover-menu--border-radius !defa
display: flex;
flex-direction: column;
align-self: flex-start;
margin: $ibo-popover-menu--section--margin-y $ibo-popover-menu--section--margin-x;
width: $ibo-popover-menu--section--height;
margin: $ibo-spacing-0 $ibo-spacing-0;
width: 100%;
white-space: nowrap;
overflow: hidden; /* To avoid first/last entries of the menu to have no border-radius on hover */

View File

@@ -6,7 +6,6 @@
@import "navigation-menu";
@import "top-bar";
@import "content";
@import "details";
@import "tab-container/tab-container";
@import "tab-container/tab";
@import "multi-column/multi-column";

View File

@@ -2,9 +2,6 @@
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
$ibo-v-spacer--padding-top: 1em !default;
$ibo-side-content--background-color: $ibo-content-block--background-color !default;
$ibo-side-content--border-left: $ibo-content-block--border !default;
/* Note: We have to wrap it in the ID in order to overload its rules, otherwise, the ID takes over the simple CSS class... */
#ibo-center-container {
@@ -19,10 +16,10 @@ $ibo-side-content--border-left: $ibo-content-block--border !default;
}
.ibo-v-spacer {
padding-top: $ibo-v-spacer--padding-top;
padding-top: 1em;
}
#ibo-side-content {
background-color: $ibo-side-content--background-color;
border-left: $ibo-side-content--border-left;
background-color: $ibo-content-block--background-color;
border-left: $ibo-content-block--border;
}

View File

@@ -1,9 +0,0 @@
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
$ibo-details--margin-top: 5px !default;
.ibo-details {
margin-top: $ibo-details--margin-top;
}

View File

@@ -218,8 +218,7 @@ $ibo-navigation-menu--user-info--height--is-expanded: 100% !default;
.ibo-navigation-menu--body{
width: $ibo-navigation-menu--body--width-expanded;
/* Values are hardcoded to ease the animation and there's no point in overloading them */
.ibo-navigation-menu--toggler-bar{
.ibo-navigation-menu--toggler-bar{
&:nth-child(1){
top: 4px;
left: 7px;
@@ -413,7 +412,6 @@ $ibo-navigation-menu--user-info--height--is-expanded: 100% !default;
transition: all 0.2s linear;
background-color: $ibo-navigation-menu--body--text-color;
/* Values are hardcoded to ease the animation and there's no point in overloading them */
&:nth-child(1){
top: 0;
}

View File

@@ -18,7 +18,6 @@ $ibo-activity-entry--medallion--has-no-image--background-color: $ibo-color-blue-
$ibo-activity-entry--medallion--has-no-image--text-color: $ibo-color-white-100 !default;
$ibo-activity-entry--medallion--has-no-image--border: 1px solid $ibo-color-grey-200 !default;
$ibo-activity-entry--information--margin-to-side: $ibo-spacing-0 !default;
$ibo-activity-entry--information--margin-to-other-side: $ibo-activity-entry--medallion--diameter + $ibo-activity-entry--medallion--margin-with-information !default;
$ibo-activity-entry--main-information--padding-x: $ibo-spacing-500 !default;
@@ -89,7 +88,7 @@ $ibo-activity-panel--load-all-entries--is-hover--margin-left: ($ibo-activity-pan
margin-left: $ibo-activity-entry--medallion--margin-with-information;
}
.ibo-activity-entry--information{
margin-right: $ibo-activity-entry--information--margin-to-side;
margin-right: 0;
margin-left: $ibo-activity-entry--information--margin-to-other-side;
}
.ibo-activity-entry--main-information{
@@ -110,7 +109,7 @@ $ibo-activity-panel--load-all-entries--is-hover--margin-left: ($ibo-activity-pan
&:not(.ibo-is-current-user){
.ibo-activity-entry--information{
margin-right: $ibo-activity-entry--information--margin-to-other-side;
margin-left: $ibo-activity-entry--information--margin-to-side;
margin-left: 0;
}
/* Bubble tip on the left for last entry of the group */
&:last-child{

View File

@@ -104,7 +104,6 @@ $ibo-activity-panel--add-caselog-entry-button--icon--line-height: 33px !default;
$ibo-activity-panel--entry-forms-confirmation-explanation--spacing: $ibo-spacing-500 !default;
$ibo-activity-panel--entry-forms-confirmation-preference-input--spacing: 0.5rem !default;
$ibo-activity-panel--closed-cover--z-index: 2 !default;
$ibo-activity-panel--closed-cover--background-color: $ibo-activity-panel--header--background-color !default;
$ibo-activity-panel--open-icon--margin-left: 0.75rem !default;
@@ -434,12 +433,14 @@ $ibo-activity-panel--open-icon--margin-left: 0.75rem !default;
.ibo-activity-panel--closed-cover {
display: none;
position: absolute;
z-index: $ibo-activity-panel--closed-cover--z-index; // Above the compose button and all
z-index: 2; // Above the compose button and all
// padding-top: 64px;
top: 0;
bottom: 0;
left: 0;
right: 0;
@extend %ibo-fully-centered-content;
// align-items: flex-start;
background-color: $ibo-activity-panel--closed-cover--background-color;
cursor: pointer;
}

View File

@@ -11,7 +11,7 @@ $ibo-caselog-entry-form--actions--margin-top: $ibo-spacing-300 !default;
$ibo-caselog-entry-form--actions--margin-bottom: $ibo-caselog-entry-form--actions--margin-top !default;
$ibo-caselog-entry-form--lock-indicator--margin-top: $ibo-caselog-entry-form--padding-bottom !default;
$ibo-caselog-entry-form--lock-icon--size: $ibo-size-350 !default;
$ibo-caselog-entry-form--lock-icon--size: 32px !default;
$ibo-caselog-entry-form--lock-icon--text-color: $ibo-color-grey-50 !default;
$ibo-caselog-entry-form--lock-icon--background-color: $ibo-color-grey-800 !default;
$ibo-caselog-entry-form--lock-icon--border-radius: $ibo-border-radius-full !default;

View File

@@ -25,10 +25,6 @@ $ibo-dashboard-editor--delete-dashlet-icon--right: 9px !default;
$ibo-dashboard-editor--delete-dashlet-icon--padding: $ibo-spacing-100 6px !default;
$ibo-dashboard-editor--delete-dashlet-icon--z-index: 21 !default;
$ibo-dashlet--properties--padding-bottom: 20px !default;
$ibo-dashlet--properties--table--width: 100% !default;
$ibo-dashlet--properties--table--cell--margin-bottom: 14px !default;
.ibo-dashboard-editor--pane{
flex-grow: 1;
@@ -51,13 +47,13 @@ $ibo-dashlet--properties--table--cell--margin-bottom: 14px !default;
.ibo-dashlet--properties{
display: flex;
flex-direction: column;
padding-bottom: $ibo-dashlet--properties--padding-bottom;
padding-bottom: 20px;
table{
width: $ibo-dashlet--properties--table--width;
width: 100%;
text-align: left;
td, th {
margin-bottom: $ibo-dashlet--properties--table--cell--margin-bottom;
margin-bottom: 14px;
.ibo-field {
@extend %ibo-font-size-100;

View File

@@ -7,38 +7,8 @@
$ibo-dashboard--grid--width: 100% !default;
$ibo-dashboard--grid--elements-spacing-x: $ibo-dashlet--elements-spacing-x !default;
$ibo-dashboard--grid--elements-spacing-y: $ibo-dashlet--elements-spacing-y !default;
$ibo-dashboard--grid--edit-mode--margin: 1px !default;
$ibo-dashboard--grid--edit-mode--border-color: $ibo-color-grey-400 !default;
$ibo-dashboard--grid--edit-mode--border: 2px $ibo-dashboard--grid--edit-mode--border-color dashed !default;
$ibo-dashboard--grid--edit-mode--width: 100% !default;
$ibo-dashboard--grid--edit-mode--min-height: 40px !default;
$ibo-dashboard--top-bar-padding-bottom: 20px !default;
$ibo-dashboard--selector--margin-left: $ibo-spacing-400 !default;
$ibo-dashboard--selector--margin-right: 1 !default;
$ibo-dashboard--selector--hover--background-color: $ibo-color-secondary-100 !default;
$ibo-dashboard--selector--hover--border-radius: $ibo-button--border-radius !default;
$ibo-dashboard--selector--selector-label--margin-x: 10px !default;
$ibo-dashboard--switch--width: 30px !default;
$ibo-dashboard--switch--height: $ibo-size-300 !default;
$ibo-dashboard--slider--before--content: "\f007" !default;
$ibo-dashboard--slider--before--font-size: $ibo-font-size-50 !default;
$ibo-dashboard--slider--before--color: $ibo-color-secondary-800 !default;
$ibo-dashboard--slider--before--right: 5px !default;
$ibo-dashboard--slider--before--bottom: 3px !default;
$ibo-dashboard--slider--after--content: "\f1ad" !default;
$ibo-dashboard--slider--after--font-size: $ibo-font-size-150 !default;
$ibo-dashboard--slider--after--color: $ibo-color-primary-600 !default;
$ibo-dashboard--slider--after--left: 6px !default;
$ibo-dashboard--slider--after--bottom: 1px !default;
/* Rules */
.ibo-dashboard--top-bar {
@extend %ibo-full-height-content;
@@ -60,18 +30,18 @@ $ibo-dashboard--slider--after--bottom: 1px !default;
.ibo-dashboard--selector {
display: flex;
align-items: center;
margin-left: $ibo-dashboard--selector--margin-left;
margin-right: $ibo-dashboard--selector--margin-right;
margin-left: 12px;
margin-right: 1px;
&:hover {
background-color: $ibo-dashboard--selector--hover--background-color;
border-radius: $ibo-dashboard--selector--hover--border-radius;
background-color: $ibo-color-secondary-100;
border-radius: $ibo-button--border-radius;
}
.selector-label {
display: inline-block;
margin-left: $ibo-dashboard--selector--selector-label--margin-x;
margin-right: $ibo-dashboard--selector--selector-label--margin-x;
margin-left: 10px;
margin-right: 10px;
vertical-align: super;
}
}
@@ -105,7 +75,7 @@ $ibo-dashboard--slider--after--bottom: 1px !default;
margin: calc(-1 * #{$ibo-dashboard--grid--elements-spacing-y} / 2) calc(-1 * #{$ibo-dashboard--grid--elements-spacing-x} / 2); /* Because of the margin all around the dashlets, we need to compensate it */
min-width: 0;
/* Compensate negative margin on inner borders to simulate equal dashlets spacing between columns */
/* Compensate negative margin on inner borders to simulate egal dashlets spacing between columns */
&:not(:last-child) {
margin-right: 0;
}
@@ -115,10 +85,10 @@ $ibo-dashboard--slider--after--bottom: 1px !default;
}
&.edit_mode {
margin: $ibo-dashboard--grid--edit-mode--margin;
border: $ibo-dashboard--grid--edit-mode--border;
width: $ibo-dashboard--grid--edit-mode--width;
min-height: $ibo-dashboard--grid--edit-mode--min-height;
margin: 1px;
border: 2px #ccc dashed;
width: 100%;
min-height: 40px;
}
}
@@ -128,8 +98,8 @@ $ibo-dashboard--slider--after--bottom: 1px !default;
.ibo-dashboard--switch {
position: relative;
display: inline-block;
width: $ibo-dashboard--switch--width;
height: $ibo-dashboard--switch--height;
width: 30px;
height: 24px;
vertical-align: baseline;
}
@@ -149,29 +119,31 @@ $ibo-dashboard--slider--after--bottom: 1px !default;
}
.ibo-dashboard--slider:before {
@extend %fa-solid-base;
content: $ibo-dashboard--slider--before--content;
font-size: $ibo-dashboard--slider--before--font-size;
color: $ibo-dashboard--slider--before--color;
position: absolute;
right: $ibo-dashboard--slider--before--right;
bottom: $ibo-dashboard--slider--before--bottom;
right: 5px;
bottom: 3px;
color: $ibo-color-secondary-800;
content: "\f007";
font-family: "Font Awesome 5 Free", serif;
font-size: $ibo-font-size-50;
font-weight: 900;
}
.ibo-dashboard--slider:after {
@extend %fa-solid-base;
content: $ibo-dashboard--slider--after--content;
font-size: $ibo-dashboard--slider--after--font-size;
color: $ibo-dashboard--slider--after--color;
position: absolute;
left: $ibo-dashboard--slider--after--left;
bottom: $ibo-dashboard--slider--after--bottom;
left: 6px;
bottom: 1px;
color: $ibo-color-primary-600;
content: "\f1ad";
font-family: "Font Awesome 5 Free", serif;
font-size: $ibo-font-size-150;
font-weight: 900;
}
input:checked + .ibo-dashboard--slider:before {
content: $ibo-dashboard--slider--after--content;
content: "\f1ad";
}
input:checked + .ibo-dashboard--slider:after {
content: $ibo-dashboard--slider--before--content;
content: "\f007";
}

View File

@@ -4,15 +4,10 @@
*/
$ibo-column--min-width: 300px !default;
$ibo-mini-column--min-width: 30px !default;
$ibo-column--padding-x: abs($ibo-multi-column--margin-x) !default;
$ibo-column--padding-y: $ibo-spacing-0 !default;
$ibo-mini-column--min-width: 30px !default;
$ibo-mini-column--padding-x: $ibo-column--padding-x !default;
$ibo-mini-column--padding-y: $ibo-column--padding-y !default;
$ibo-mini-column--button-margin-left: $ibo-spacing-0 !default;
$ibo-mini-column--button-margin-right: $ibo-spacing-0 !default;
$ibo-column--margin-bottom--is-last-element: $ibo-spacing-800 !default;
.ibo-column {
@@ -31,14 +26,14 @@ $ibo-column--margin-bottom--is-last-element: $ibo-spacing-800 !default;
min-width: $ibo-mini-column--min-width;
flex-grow: 1;
flex-shrink: 1;
padding: $ibo-mini-column--padding-y $ibo-mini-column--padding-x;
padding: $ibo-column--padding-y $ibo-column--padding-x;
flex-basis: 10%;
display: flex;
flex-direction: column;
>.ibo-button{
margin-left: $ibo-mini-column--button-margin-left;
margin-right: $ibo-mini-column--button-margin-right;
margin-left: 0;
margin-right: 0;
}
&:not(:last-child) {
margin-bottom: $ibo-column--margin-bottom--is-last-element;

View File

@@ -3,7 +3,7 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
$ibo-multi-column--margin-x: -$ibo-spacing-500 !default; /* This is to compensate columns padding and make the whole multicolumn align with the parent borders (cf. Bootstrap rows / cols) */
$ibo-multi-column--margin-x: -16px !default; /* This is to compensate columns padding and make the whole multicolumn align with the parent borders (cf. Bootstrap rows / cols) */
$ibo-multi-column--margin-y: $ibo-spacing-0 !default;
.ibo-multi-column {

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