@@ -547,24 +547,22 @@ private function manageFieldValues()
547547
548548
549549 /**
550- * Get the ID associated with a value from the CSV file
551- *
552- * @param PluginDatainjectionInjectionInterface|null $injectionClass
553- * @param string $itemtype itemtype of the values to inject
554- * @param array $searchOption option associated with the field to check
555- * @param string $field the field to check
556- * @param string $value the value coming from the CSV file
557- * @param boolean $add is insertion (true) or update (false) (true by default)
558- *
559- * @return void nothing
560- **/
550+ * Get the ID associated with a value from the CSV file
551+ *
552+ * @param PluginDatainjectionInjectionInterface|null $injectionClass
553+ * @param string $itemtype itemtype of the values to inject
554+ * @param array $searchOption option associated with the field to check
555+ * @param string $field the field to check
556+ * @param string $value the value coming from the CSV file
557+ *
558+ * @return void nothing
559+ **/
561560 private function getFieldValue (
562561 $ injectionClass ,
563562 $ itemtype ,
564563 $ searchOption ,
565564 $ field ,
566- $ value ,
567- $ add = true
565+ $ value
568566 ) {
569567 if (isset ($ searchOption ['storevaluein ' ])) {
570568 $ linkfield = $ searchOption ['storevaluein ' ];
@@ -583,13 +581,12 @@ private function getFieldValue(
583581 break ;
584582
585583 case 'password ' :
586- //To add a user password, it's mandatory is give a password and it's confirmation
587- //Here we cannot detect if it's an add or update. We'll handle updates later in the process
588- if ($ add && $ itemtype == 'User ' ) {
584+ //Core needs both the password and its confirmation to validate and hash it, on add as well as on update
585+ if ($ itemtype == 'User ' ) {
589586 $ this ->setValueForItemtype ($ itemtype , $ linkfield , $ value );
590- //Add field password2 is not already present
587+ //Add field password2 if not already present
591588 //(can be present if password was an addtional information)
592- if (!isset ($ this ->values [$ itemtype ][$ field ])) {
589+ if (!isset ($ this ->values [$ itemtype ][$ linkfield . " 2 " ])) {
593590 $ this ->setValueForItemtype ($ itemtype , $ linkfield . "2 " , $ value );
594591 }
595592 }
@@ -927,7 +924,8 @@ private function unsetValue($itemtype, $field)
927924 **/
928925 private function setValueForItemtype ($ itemtype , $ field , $ value , $ fromdb = false )
929926 {
930- if ($ itemtype === User::class && $ field === "pdffont " && $ fromdb ) {
927+ //The stored password is a hash: taking it back from the DB would overwrite the imported one
928+ if ($ itemtype === User::class && in_array ($ field , ['pdffont ' , 'password ' ], true ) && $ fromdb ) {
931929 return ;
932930 }
933931 $ injectionClass = self ::getInjectionClassInstance ($ itemtype );
@@ -1577,14 +1575,17 @@ public function processAddOrUpdate()
15771575 $ newID = $ this ->effectiveAddOrUpdate ($ this ->injectionClass , $ item , $ values , $ add );
15781576
15791577 if (!$ newID ) {
1580- $ this ->results [ ' status ' ] = self ::WARNING ;
1578+ $ this ->addCheckWarning ( self ::WARNING , get_class ( $ item )) ;
15811579 } else {
15821580 //Store id of the injected item
15831581 $ this ->setValueForItemtype ($ this ->primary_type , 'id ' , $ newID );
15841582
1585- //If type needs it : process more data after type import
1586- $ this ->processAfterInsertOrUpdate ($ this ->injectionClass , $ add );
1587- //$this->results['status'] = self::SUCCESS;
1583+ //If type needs it : process more data after type import
1584+ if ($ this ->processAfterInsertOrUpdate ($ this ->injectionClass , $ add ) === false ) {
1585+ $ this ->addCheckWarning (self ::WARNING , get_class ($ item ));
1586+ }
1587+
1588+ //$this->results['status'] = self::SUCCESS;
15881589 $ this ->results [get_class ($ item )] = $ newID ;
15891590
15901591 //Process other types
@@ -1619,7 +1620,11 @@ public function processAddOrUpdate()
16191620 $ values = $ this ->getValuesForItemtype ($ itemtype );
16201621 if ($ this ->lastCheckBeforeProcess ($ injectionClass , $ values )) {
16211622 $ tmpID = $ this ->effectiveAddOrUpdate ($ injectionClass , $ item , $ values , $ add );
1622- $ this ->processAfterInsertOrUpdate ($ injectionClass , $ add );
1623+ if (!$ tmpID ) {
1624+ $ this ->addCheckWarning (self ::WARNING , $ itemtype );
1625+ } elseif ($ this ->processAfterInsertOrUpdate ($ injectionClass , $ add ) === false ) {
1626+ $ this ->addCheckWarning (self ::WARNING , $ itemtype );
1627+ }
16231628 }
16241629 }
16251630 }
@@ -1630,6 +1635,20 @@ public function processAddOrUpdate()
16301635 }
16311636
16321637
1638+ /**
1639+ * Flag the current line as partially injected and log the reason
1640+ *
1641+ * @param integer $code log label describing the reason
1642+ * @param string $itemtype itemtype that could not be written
1643+ **/
1644+ private function addCheckWarning (int $ code , string $ itemtype ): void
1645+ {
1646+ $ this ->results ['status ' ] = self ::WARNING ;
1647+ $ this ->results [self ::ACTION_CHECK ]['status ' ] = self ::WARNING ;
1648+ $ this ->results [self ::ACTION_CHECK ][] = [$ code , $ itemtype ];
1649+ }
1650+
1651+
16331652 /**
16341653 * Perform data injection into GLPI DB
16351654 *
@@ -1643,7 +1662,25 @@ public function processAddOrUpdate()
16431662 private function effectiveAddOrUpdate ($ injectionClass , $ item , $ values , $ add = true )
16441663 {
16451664
1646- //Insert data using the standard add() method
1665+ //The plugin acts as the front controller here: rights must be checked before writing.
1666+ //Skipped without a session, as the lib is also a programmatic entry point for scripts.
1667+ if (Session::getLoginUserID () !== false ) {
1668+ $ input = is_array ($ values ) ? $ values : [];
1669+ if ($ add ) {
1670+ //Passing the input to can() makes the check cover the target entity
1671+ if (!$ item ->can (-1 , CREATE , $ input )) {
1672+ $ this ->addCheckWarning (self ::ERROR_CANNOT_IMPORT , get_class ($ item ));
1673+ return 0 ;
1674+ }
1675+
1676+ //On the update path the target id is known, so the per-item check also covers the entity scope
1677+ } elseif (!isset ($ values ['id ' ]) || !$ item ->can ($ values ['id ' ], UPDATE )) {
1678+ $ this ->addCheckWarning (self ::ERROR_CANNOT_UPDATE , get_class ($ item ));
1679+ return 0 ;
1680+ }
1681+ }
1682+
1683+ //Insert data using the standard add() method
16471684 $ toinject = [];
16481685 $ options = $ injectionClass ->getOptions ();
16491686
@@ -1816,7 +1853,6 @@ private function manageRelations()
18161853 $ option ,
18171854 $ option ['linkfield ' ],
18181855 $ value ,
1819- true
18201856 );
18211857 }
18221858 }
@@ -2317,15 +2353,17 @@ public static function addTemplateSearchOptions($injectionClass, &$tab)
23172353 * @param PluginDatainjectionInjectionInterface $injectionClass the injection class to use
23182354 * @param $add true if an item is created, false if it's an update
23192355 *
2320- * @return void nothing
2356+ * @return bool false if the injection class rejected a post-processing step
23212357 **/
23222358 private function processAfterInsertOrUpdate ($ injectionClass , $ add = true )
23232359 {
23242360
23252361 //If itemtype implements special process after type injection
23262362 if (method_exists ($ injectionClass , 'processAfterInsertOrUpdate ' )) {
2327- //Invoke it
2328- $ injectionClass ->processAfterInsertOrUpdate ($ this ->values , $ add , $ this ->rights );
2363+ //Invoke it
2364+ return $ injectionClass ->processAfterInsertOrUpdate ($ this ->values , $ add , $ this ->rights ) !== false ;
23292365 }
2366+
2367+ return true ;
23302368 }
23312369}
0 commit comments