r2137 - fix tag roller 'OK' message
authorDenis Ovsienko <infrastation@yandex.ru>
Thu, 14 Aug 2008 19:47:42 +0000 (19:47 +0000)
committerDenis Ovsienko <infrastation@yandex.ru>
Thu, 14 Aug 2008 19:47:42 +0000 (19:47 +0000)
 - introduce and use tagOnChain(), tagOnIdList() and tagChainCmp()
 - make tag roller process objects in the racks as well
 - make tag roller produce minimal tag base possible
 - merge tagChainFromIdList() and buildTagChainFromIds()
 - convert getObjectCount() into stuffInRackspace()

inc/database.php
inc/functions.php
inc/interface.php
inc/navigation.php
inc/ophandlers.php

index 49e76b8..ad1cb8e 100644 (file)
@@ -2811,13 +2811,30 @@ function addTagForEntity ($realm, $entity_id, $tag_id)
 }
 
 // Add records into TagStorage, if this makes sense (IOW, they don't appear
-// on the implicit list already). If this happened, remove any other records,
-// which could shift to the "implicit" side of the chain. This will make sure,
+// on the implicit list already). Then remove any other records, which
+// appear on the "implicit" side of the chain. This will make sure,
 // that both the tag base is still minimal and all requested tags appear on
 // the resulting tag chain.
-function appendTagsForEntity ($realm, $entity_id, $tagidlist)
-{
-       return;
+// Return TRUE, if any changes were committed.
+function rebuildTagChainForEntity ($realm, $entity_id, $extrachain = array())
+{
+       // Put the current explicit sub-chain into a buffer and merge all tags from
+       // the extra chain, which aren't there yet.
+       $newchain = $oldchain = loadEntityTags ($realm, $entity_id);
+       foreach ($extrachain as $extratag)
+               if (!tagOnChain ($extratag, $newchain))
+                       $newchain[] = $extratag;
+       // Then minimize the working buffer and check if it differs from the original
+       // chain we started with. If it is so, save the work and signal the upper layer.
+       $newchain = getExplicitTagsOnly ($newchain);
+       if (tagChainCmp ($oldchain, $newchain))
+       {
+               deleteTagsForEntity ($realm, $entity_id);
+               foreach ($newchain as $taginfo)
+                       addTagForEntity ($realm, $entity_id, $taginfo['id']);
+               return TRUE;
+       }
+       return FALSE;
 }
 
 // Presume, that the target record has no tags attached.
@@ -2828,7 +2845,7 @@ function produceTagsForLastRecord ($realm, $tagidlist, $last_insert_id = 0)
        if (!$last_insert_id)
                $last_insert_id = lastInsertID();
        $errcount = 0;
-       foreach (getExplicitTagsOnly (tagChainFromIdList ($tagidlist)) as $taginfo)
+       foreach (getExplicitTagsOnly (buildTagChainFromIds ($tagidlist)) as $taginfo)
                if (addTagForEntity ($realm, $last_insert_id, $taginfo['id']) == FALSE)
                        $errcount++;    
        if (!$errcount)
index ea3dd3f..a3294b3 100644 (file)
@@ -859,7 +859,8 @@ function getRSUforRackRow ($rowData = NULL)
        return ($counter['T'] + $counter['W'] + $counter['U']) / ($counter['T'] + $counter['W'] + $counter['U'] + $counter['F']);
 }
 
-function getObjectCount ($rackData)
+// Return a list of object IDs, which can be found in the given rackspace block.
+function stuffInRackspace ($rackData)
 {
        $objects = array();
        for ($i = $rackData['height']; $i > 0; $i--)
@@ -870,7 +871,7 @@ function getObjectCount ($rackData)
                                !in_array ($rackData[$i][$locidx]['object_id'], $objects)
                        )
                                $objects[] = $rackData[$i][$locidx]['object_id'];
-       return count ($objects);
+       return $objects;
 }
 
 // Make sure the string is always wrapped with LF characters
@@ -1142,18 +1143,6 @@ function complementByKids ($idlist, $tree = NULL, $getall = FALSE)
        return $ret;
 }
 
-// Take a list of user-supplied tag IDs to build a list of valid taginfo
-// records indexed by tag IDs (tag chain).
-function tagChainFromIdList ($tagidlist)
-{
-       global $taglist;
-       $ret = array();
-       foreach (array_unique ($tagidlist) as $tagid)
-               if (isset ($taglist[$tagid]))
-                       $ret[$tagid] = $taglist[$tagid];
-       return $ret;
-}
-
 function getUserAutoTags ($username = NULL)
 {
        global $remote_username, $accounts;
@@ -1241,6 +1230,42 @@ function loadIPv4RSPoolAutoTags ()
        return $ret;
 }
 
+// Check, if the given tag is present on the chain (will only work
+// for regular tags with tag ID set.
+function tagOnChain ($taginfo, $tagchain)
+{
+       if (!isset ($taginfo['id']))
+               return FALSE;
+       foreach ($tagchain as $test)
+               if ($test['id'] == $taginfo['id'])
+                       return TRUE;
+       return FALSE;
+}
+
+// Idem, but use ID list instead of chain.
+function tagOnIdList ($taginfo, $tagidlist)
+{
+       if (!isset ($taginfo['id']))
+               return FALSE;
+       foreach ($tagidlist as $tagid)
+               if ($test['id'] == $tagid)
+                       return TRUE;
+       return FALSE;
+}
+
+// Return TRUE, if two tags chains differ (order of tags doesn't matter).
+// Assume, that neither of the lists contains duplicates.
+// FIXME: a faster, than O(x^2) method is possible for this calculation.
+function tagChainCmp ($chain1, $chain2)
+{
+       if (count ($chain1) != count ($chain2))
+               return TRUE;
+       foreach ($chain1 as $taginfo1)
+               if (!tagOnChain ($taginfo1, $chain2))
+                       return TRUE;
+       return FALSE;
+}
+
 // If the page-tab-op triplet is final, make $expl_tags and $impl_tags
 // hold all appropriate (explicit and implicit) tags respectively.
 // Otherwise some limited redirection is necessary (only page and tab
@@ -1283,12 +1308,13 @@ function fixContext ()
        }
 }
 
-// Build a tag chain from supplied tag id list and return it.
+// Take a list of user-supplied tag IDs to build a list of valid taginfo
+// records indexed by tag IDs (tag chain).
 function buildTagChainFromIds ($tagidlist)
 {
        global $taglist;
        $ret = array();
-       foreach ($tagidlist as $tag_id)
+       foreach (array_unique ($tagidlist) as $tag_id)
                if (isset ($taglist[$tag_id]))
                        $ret[] = $taglist[$tag_id];
        return $ret;
index 5d6032d..6ea4e86 100644 (file)
@@ -620,7 +620,7 @@ function renderRackInfoPortlet ($rackData)
        renderProgressBar (getRSUforRack ($rackData));
        echo "</td></tr>\n";
        echo "<tr><th width='50%' class=tdright>Objects:</th><td class=tdleft>";
-       echo getObjectCount ($rackData);
+       echo count (stuffInRackspace ($rackData));
        echo "</td></tr>\n";
        printTagTRs ("${root}?page=rackspace&");
        if (!empty ($rackData['comment']))
@@ -1289,6 +1289,7 @@ function printLog ($log)
                                64 => array ('code' => 'success', 'format' => 'Port %s@%s has been assigned to VLAN %u'),
                                65 => array ('code' => 'success', 'format' => "Added new rack '%s'"),
                                66 => array ('code' => 'success', 'format' => "File sent Ok via handler '%s'"),
+                               67 => array ('code' => 'success', 'format' => "Tag rolling done, %u objects involved"),
 
                                100 => array ('code' => 'error', 'format' => 'Generic error: %s'),
                                101 => array ('code' => 'error', 'format' => 'Port name cannot be empty'),
@@ -4739,13 +4740,7 @@ function renderTagTreeEditor ()
 function renderTagOption ($taginfo, $level = 0)
 {
        global $expl_tags;
-       $selected = '';
-       foreach ($expl_tags as $etaginfo)
-               if ($taginfo['id'] == $etaginfo['id'])
-               {
-                       $selected = ' selected';
-                       break;
-               }
+       $selected = tagOnChain ($taginfo, $expl_tags) ? ' selected' : '';
        echo '<option value=' . $taginfo['id'] . "${selected}>";
        for ($i = 0; $i < $level; $i++)
                echo '-- ';
@@ -4758,13 +4753,7 @@ function renderTagOption ($taginfo, $level = 0)
 // Ignore tag ids, which can't be found on the tree.
 function renderTagOptionForFilter ($taginfo, $tagfilter, $realm, $level = 0)
 {
-       $selected = '';
-       foreach ($tagfilter as $filter_id)
-               if ($taginfo['id'] == $filter_id)
-               {
-                       $selected = ' selected';
-                       break;
-               }
+       $selected = tagOnIdList ($taginfo, $tagfilter) ?' selected' : '';
        echo '<option value=' . $taginfo['id'] . "${selected}>";
        for ($i = 0; $i < $level; $i++)
                echo '-- ';
@@ -4903,7 +4892,7 @@ function renderTagRollerForRow ($row_id)
        showMessageOrError();
        printOpFormIntro ('rollTags', array ('realsum' => $sum));
        echo "<table border=1 align=center>";
-       echo "<tr><td colspan=2>This special tool allows assigning tags to physical contents (racks <s>and contained objects</s>) of the current ";
+       echo "<tr><td colspan=2>This special tool allows assigning tags to physical contents (racks <strong>and all contained objects</strong>) of the current ";
        echo "rack row.<br>The tag(s) selected below will be ";
        echo "appended to already assigned tag(s) of each particular entity. </td></tr>";
        echo "<tr><th>Tags</th><td>";
index 34a18fb..ef35547 100644 (file)
@@ -47,7 +47,7 @@ $tabhandler['row']['newrack'] = 'renderNewRackForm';
 $tabhandler['row']['tagroller'] = 'renderTagRollerForRow';
 $ophandler['row']['tagroller']['rollTags'] = 'rollTags';
 $ophandler['row']['newrack']['addRack'] = 'addRack';
-$msgcode['row']['tagroller']['rollTags']['OK'] = 1;
+$msgcode['row']['tagroller']['rollTags']['OK'] = 67;
 $msgcode['row']['tagroller']['rollTags']['ERR'] = 149;
 $msgcode['row']['newrack']['addRack']['OK'] = 65;
 $msgcode['row']['newrack']['addRack']['ERR1'] = 171;
index f557964..4b66bd7 100644 (file)
@@ -1230,24 +1230,25 @@ function rollTags ()
        assertUIntArg ('row_id', __FUNCTION__);
        assertStringArg ('sum', __FUNCTION__, TRUE);
        assertUIntArg ('realsum', __FUNCTION__);
-       $row_id = $_REQUEST['row_id'];
        if ($_REQUEST['sum'] != $_REQUEST['realsum'])
                return buildRedirectURL ('ERR');
-       $racks = getRacksForRow ($row_id);
-       // Each time addTagForEntity() fails we assume it was just because of already existing record in its way.
-       $newtags = isset ($_REQUEST['taglist']) ? $_REQUEST['taglist'] : array();
-       $tagstack = getExplicitTagsOnly (buildTagChainFromIds ($newtags));
-       $ndupes = $nnew = 0;
-       foreach ($tagstack as $taginfo)
-               foreach ($racks as $rackInfo)
-               {
-                       if (addTagForEntity ('rack', $rackInfo['id'], $taginfo['id']))
-                               $nnew++;
-                       else
-                               $ndupes++;
-                       // FIXME: do something likewise for all object inside current rack
-               }
-       return buildRedirectURL ('OK', array ($nnew, $ndupes));
+       // Even if the user requested an empty tag list, don't bail out, but process existing
+       // tag chains with "zero" extra. This will make sure, that the stuff processed will
+       // have its chains refined to "normal" form.
+       $extratags = isset ($_REQUEST['taglist']) ? $_REQUEST['taglist'] : array();
+       $n_ok = 0;
+       // Minimizing the extra chain early, so that tag rebuilder doesn't have to
+       // filter out the same tag again and again. It will have own noise to cancel.
+       $extrachain = getExplicitTagsOnly (buildTagChainFromIds ($extratags));
+       foreach (getRacksForRow ($_REQUEST['row_id']) as $rackInfo)
+       {
+               if (rebuildTagChainForEntity ('rack', $rackInfo['id'], $extrachain))
+                       $n_ok++;
+               foreach (stuffInRackspace (getRackData ($rackInfo['id'])) as $object_id)
+                       if (rebuildTagChainForEntity ('object', $object_id, $extrachain))
+                               $n_ok++;
+       }
+       return buildRedirectURL ('OK', array ($n_ok));
 }
 
 function changeMyPassword ()