Fix tag item association - #372
Conversation
4024518 to
e9c3d61
Compare
e9c3d61 to
569201f
Compare
2b655a6 to
0a31762
Compare
| echo "<div class='firstbloc'>"; | ||
| echo "<form name='tagitem_form{$rand}' id='tagitem_form{$rand}' method='post' | ||
| action='" . Toolbox::getItemTypeFormURL('PluginTagTag') . "'>"; | ||
| action='" . plugin_tag_geturl() . "/ajax/add_item_to_tag.php'>"; |
There was a problem hiding this comment.
This association should not be handled through an AJAX file.
Instead, a dedicated controller should be created for TagItem. It should handle the add action, which should be renamed to associate to better reflect its purpose.
| $tagItem = new PluginTagTagItem(); | ||
| $tagItem->add([ |
There was a problem hiding this comment.
| $tagItem = new PluginTagTagItem(); | |
| $tagItem->add([ | |
| $this->createItem(PluginTagTagItem::class, [ |
| $tag = new PluginTagTag(); | ||
| $tag->add( | ||
| [ | ||
| 'name' => $tagName, | ||
| 'is_active' => 1, | ||
| 'type_menu' => ['Ticket'], | ||
| 'type_menu' => $typeMenu, | ||
| ], | ||
| ); | ||
| $this->assertGreaterThan(0, $tag->getID()); |
There was a problem hiding this comment.
| $tag = new PluginTagTag(); | |
| $tag->add( | |
| [ | |
| 'name' => $tagName, | |
| 'is_active' => 1, | |
| 'type_menu' => ['Ticket'], | |
| 'type_menu' => $typeMenu, | |
| ], | |
| ); | |
| $this->assertGreaterThan(0, $tag->getID()); | |
| $tag = $this->createItem(PluginTagTag::class, [ | |
| 'name' => $tagName, | |
| 'is_active' => 1, | |
| 'type_menu' => $typeMenu, | |
| ], ['type_menu']); |
| $this->isItemTagged($ticket, $tagID2); | ||
| } | ||
|
|
||
| public function testTagAssociationCreatesLink(): void |
There was a problem hiding this comment.
testTagAssociationCreatesLink() creates a PluginTagTagItem directly via createItem(),
bypassing the controller entirely. The original regression was a missing route handler — if
the controller is removed again, this test still passes. A test that POSTs to
/plugins/tag/associate is needed to actually guard against the regression.
There was a problem hiding this comment.
This test builds the PluginTagTagItem link directly via createItem(), bypassing TagItemController::associate entirely. Since the original regression was exactly this route handler going missing, can you add a test that POSTs to /plugins/tag/associate instead (or in addition), so a future removal of the controller/route is actually caught?
|
|
||
| final class TagItemController extends GenericFormController | ||
| { | ||
| #[Route('/associate', methods: ['POST'])] |
There was a problem hiding this comment.
| #[Route('/associate', methods: ['POST'])] | |
| #[ItemtypeFormRoute(PluginTagTagItem::class)] |
| public function associate(Request $request): Response | ||
| { | ||
| Session::checkLoginUser(); | ||
|
|
||
| $tag_id = $request->request->getInt('plugin_tag_tags_id'); | ||
| $itemtype = $request->request->get('itemtype'); | ||
| $item_id = $request->request->getInt('items_id'); | ||
|
|
||
| if (!$tag_id || !$itemtype || !$item_id) { | ||
| throw new BadRequestHttpException(__s('Missing parameters', 'tag')); | ||
| } | ||
|
|
||
| $tag = new PluginTagTag(); | ||
| if (!$tag->getFromDB($tag_id) || !$tag->can($tag_id, UPDATE)) { | ||
| throw new AccessDeniedHttpException(__s('You do not have permission to update this tag', 'tag')); | ||
| } | ||
|
|
||
| if (!is_a($itemtype, CommonDBTM::class, true) || !PluginTagTag::canItemtype($itemtype)) { | ||
| throw new BadRequestHttpException(__s('Invalid item type', 'tag')); | ||
| } | ||
|
|
||
| $item = new $itemtype(); | ||
| if (!$item->getFromDB($item_id) || !$item->canUpdateItem()) { | ||
| throw new AccessDeniedHttpException(__s('You do not have permission to update this item', 'tag')); | ||
| } | ||
|
|
||
| $tag_item = new PluginTagTagItem(); | ||
| $found = $tag_item->find([ | ||
| 'plugin_tag_tags_id' => $tag_id, | ||
| 'items_id' => $item_id, | ||
| 'itemtype' => $itemtype, | ||
| ]); | ||
|
|
||
| if (count($found) === 0) { | ||
| $tag_item->add([ | ||
| 'plugin_tag_tags_id' => $tag_id, | ||
| 'items_id' => $item_id, | ||
| 'itemtype' => $itemtype, | ||
| ]); | ||
| } | ||
|
|
||
| return new RedirectResponse(Html::getBackUrl()); | ||
| } |
There was a problem hiding this comment.
| public function associate(Request $request): Response | |
| { | |
| Session::checkLoginUser(); | |
| $tag_id = $request->request->getInt('plugin_tag_tags_id'); | |
| $itemtype = $request->request->get('itemtype'); | |
| $item_id = $request->request->getInt('items_id'); | |
| if (!$tag_id || !$itemtype || !$item_id) { | |
| throw new BadRequestHttpException(__s('Missing parameters', 'tag')); | |
| } | |
| $tag = new PluginTagTag(); | |
| if (!$tag->getFromDB($tag_id) || !$tag->can($tag_id, UPDATE)) { | |
| throw new AccessDeniedHttpException(__s('You do not have permission to update this tag', 'tag')); | |
| } | |
| if (!is_a($itemtype, CommonDBTM::class, true) || !PluginTagTag::canItemtype($itemtype)) { | |
| throw new BadRequestHttpException(__s('Invalid item type', 'tag')); | |
| } | |
| $item = new $itemtype(); | |
| if (!$item->getFromDB($item_id) || !$item->canUpdateItem()) { | |
| throw new AccessDeniedHttpException(__s('You do not have permission to update this item', 'tag')); | |
| } | |
| $tag_item = new PluginTagTagItem(); | |
| $found = $tag_item->find([ | |
| 'plugin_tag_tags_id' => $tag_id, | |
| 'items_id' => $item_id, | |
| 'itemtype' => $itemtype, | |
| ]); | |
| if (count($found) === 0) { | |
| $tag_item->add([ | |
| 'plugin_tag_tags_id' => $tag_id, | |
| 'items_id' => $item_id, | |
| 'itemtype' => $itemtype, | |
| ]); | |
| } | |
| return new RedirectResponse(Html::getBackUrl()); | |
| } | |
| public function associate(Request $request): Response | |
| { | |
| if ($request->query->getInt('associate') === 1) { | |
| Session::checkLoginUser(); | |
| $tag_id = $request->request->getInt('plugin_tag_tags_id'); | |
| $itemtype = $request->request->get('itemtype'); | |
| $item_id = $request->request->getInt('items_id'); | |
| if (!$tag_id || !$itemtype || !$item_id) { | |
| throw new BadRequestHttpException(__s('Missing parameters', 'tag')); | |
| } | |
| $tag = new PluginTagTag(); | |
| if (!$tag->getFromDB($tag_id) || !$tag->can($tag_id, UPDATE)) { | |
| throw new AccessDeniedHttpException(__s('You do not have permission to update this tag', 'tag')); | |
| } | |
| if (!is_a($itemtype, CommonDBTM::class, true) || !PluginTagTag::canItemtype($itemtype)) { | |
| throw new BadRequestHttpException(__s('Invalid item type', 'tag')); | |
| } | |
| $item = new $itemtype(); | |
| if (!$item->getFromDB($item_id) || !$item->canUpdateItem()) { | |
| throw new AccessDeniedHttpException(__s('You do not have permission to update this item', 'tag')); | |
| } | |
| $tag_item = new PluginTagTagItem(); | |
| $found = $tag_item->find([ | |
| 'plugin_tag_tags_id' => $tag_id, | |
| 'items_id' => $item_id, | |
| 'itemtype' => $itemtype, | |
| ]); | |
| if (count($found) === 0) { | |
| $tag_item->add([ | |
| 'plugin_tag_tags_id' => $tag_id, | |
| 'items_id' => $item_id, | |
| 'itemtype' => $itemtype, | |
| ]); | |
| } | |
| return new RedirectResponse(Html::getBackUrl()); | |
| } | |
| } |
| ]); | ||
| echo "</td><td width='20%'>"; | ||
| echo sprintf("<input type='hidden' name='plugin_tag_tags_id' value='%s'>", $instID); | ||
| echo "<input type='submit' name='add' value=\"" . _sx('button', 'Add') . "\" class='btn btn-primary'>"; |
There was a problem hiding this comment.
| echo "<input type='submit' name='associate' value=\"" . _sx('button', 'Add') . "\" class='btn btn-primary'>"; |
| echo "<div class='firstbloc'>"; | ||
| echo "<form name='tagitem_form{$rand}' id='tagitem_form{$rand}' method='post' | ||
| action='" . Toolbox::getItemTypeFormURL('PluginTagTag') . "'>"; | ||
| action='/plugins/tag/associate'>"; |
There was a problem hiding this comment.
| action='/plugins/tag/associate'>"; | |
| action='" . Toolbox::getItemTypeFormURL('PluginTagTagItem') . "'>"; |
Checklist before requesting a review
Please delete options that are not relevant.
Description
Regression : The file front/tag.form.php, which handled this association, had been accidentally deleted in an unrelated commit. The request was then processed by the generic mechanism, which created a tag instead of establishing the association.
Fix : re-enable correct processing of the tag/item association.
Screenshots (if appropriate):