2770a53d1e8e0e5773020965d19c2499439481ca
chmalee
  Tue Feb 7 13:33:08 2023 -0800
Make hubApi return data from multiple tracks at once. Get trackDb tableBrowser setting working correctly in the api

diff --git src/hg/cgilib/cartTrackDb.c src/hg/cgilib/cartTrackDb.c
index 36d2a5c..5a906e7 100644
--- src/hg/cgilib/cartTrackDb.c
+++ src/hg/cgilib/cartTrackDb.c
@@ -48,36 +48,39 @@
     char *tbOff = trackDbSetting(tdb, "tableBrowser");
     if (useAC && tbOff != NULL &&
         (startsWithWord("off", tbOff) || startsWithWord("noGenome", tbOff) || startsWithWord("tbNoGenome", tbOff)))
         {
         slAddHead(&accessControlTrackRefList, slRefNew(tdb));
         if (! startsWithWord("off", tbOff))
             slAddHead(&newList, tdb);
         }
     else
 	slAddHead(&newList, tdb);
     }
 slReverse(&newList);
 list = newList;
 
 // Add custom tracks at head of list
+if (cart)
+    {
     struct customTrack *ctList, *ct;
     ctList = customTracksParseCart(db, cart, NULL, NULL);
     for (ct = ctList; ct != NULL; ct = ct->next)
         {
         slAddHead(&list, ct->tdb);
         }
+    }
 
 return list;
 }
 
 static struct grp *makeGroupList(char *db, struct trackDb *trackList, struct grp **pHubGrpList,
                                  boolean allTablesOk)
 /* Get list of groups that actually have something in them. */
 {
 struct grp *groupsAll, *groupList = NULL, *group;
 struct hash *groupsInTrackList = newHash(0);
 struct hash *groupsInDatabase = newHash(0);
 struct trackDb *track;
 
 /* Do some error checking for tracks with group names that are not in database.
  * Warnings at this stage mess up CGIs that may produce text output like hgTables & hgIntegrator,
@@ -174,30 +177,45 @@
  * If useAccessControl, exclude tracks with 'tableBrowser off' nor tables listed
  * in the table tableAccessControl. */
 {
 char *db = cartString(cart, "db");
 useAC = useAccessControl;
 struct grp *hubGrpList = NULL;
 struct trackDb *fullTrackList = getFullTrackList(cart, db, &hubGrpList);
 boolean allTablesOk = hAllowAllTables() && !trackHubDatabase(db);
 struct grp *fullGroupList = makeGroupList(db, fullTrackList, &hubGrpList, allTablesOk);
 if (retFullTrackList != NULL)
     *retFullTrackList = fullTrackList;
 if (retFullGroupList != NULL)
     *retFullGroupList = fullGroupList;
 }
 
+void cartTrackDbInitForApi(struct cart *cart, char *db, struct trackDb **retFullTrackList,
+                     struct grp **retFullGroupList, boolean useAccessControl)
+/* Similar to cartTrackDbInit, but allow cart to be NULL */
+{
+useAC = useAccessControl;
+struct grp *hubGrpList = NULL;
+struct trackDb *fullTrackList = getFullTrackList(cart, db, &hubGrpList);
+boolean allTablesOk = hAllowAllTables() && !trackHubDatabase(db);
+struct grp *fullGroupList = makeGroupList(db, fullTrackList, &hubGrpList, allTablesOk);
+if (retFullTrackList != NULL)
+    *retFullTrackList = fullTrackList;
+if (retFullGroupList != NULL)
+    *retFullGroupList = fullGroupList;
+}
+
 static char *chopAtFirstDot(char *string)
 /* Terminate string at first '.' if found.  Return string for convenience. */
 {
 char *ptr = strchr(string, '.');
 if (ptr != NULL)
     *ptr = '\0';
 return string;
 }
 
 struct accessControl
 /* Restricted permission settings for a table */
     {
     struct slName *hostList;       // List of hosts that are allowed to view this table
     boolean isNoGenome;            // True if it's OK for position range but not genome-wide query
     };
@@ -249,51 +267,76 @@
     if (sqlTableExists(conn, "tableAccessControl"))
         {
         struct sqlResult *sr = NULL;
         char **row = NULL;
         acHash = newHash(0);
 	char query[1024];
 	sqlSafef(query, sizeof query, "select name,host from tableAccessControl");
         sr = sqlGetResult(conn, query);
         while ((row = sqlNextRow(sr)) != NULL)
             acHashAddOneTable(acHash, row[0], chopAtFirstDot(row[1]), FALSE);
         sqlFreeResult(&sr);
         }
     hFreeConn(&conn);
     }
 struct slRef *tdbRef;
+
+// init accessControlTrackRefList
+if (!accessControlTrackRefList)
+    {
+    boolean oldAC = useAC;
+    useAC = TRUE;
+    (void)getFullTrackList(NULL, db, NULL);
+    useAC = oldAC;
+    }
 for (tdbRef = accessControlTrackRefList; tdbRef != NULL; tdbRef = tdbRef->next)
     {
     struct trackDb *tdb = tdbRef->val;
     char *tbOff = cloneString(trackDbSetting(tdb, "tableBrowser"));
     if (isEmpty(tbOff))
         errAbort("accessControlInit bug: tdb for %s does not have tableBrowser setting",
                  tdb->track);
     // First word is "off" or "noGenome" or "tbNoGenome":
     char *type = nextWord(&tbOff);
 
     boolean isNoGenome = sameString(type, "noGenome");
     if (!isNoGenome)
-        isNoGenome = sameString(type, "tbNoGenome"); // like 'noGenome' but only in the table browser, not the API 
+        isNoGenome = sameString(type, "off") || sameString(type, "tbNoGenome"); // like 'noGenome' but only in the table browser, not the API 
         // since the API does not use this function
 
     // Add track table to acHash:
     acHashAddOneTable(acHash, tdb->table, NULL, isNoGenome);
     // Remaining words are additional table names to add:
     char *tbl;
     while ((tbl = nextWord(&tbOff)) != NULL)
         acHashAddOneTable(acHash, tbl, NULL, isNoGenome);
+    // add any subtracks that don't have their own setting overriding us
+    struct trackDb *subTdb;
+    for (subTdb = tdb->subtracks; subTdb != NULL; subTdb = subTdb->next)
+        {
+        char *subTdbOff = cloneString(trackDbSetting(tdb, "tableBrowser"));
+        if (!subTdbOff)
+            acHashAddOneTable(acHash, subTdb->table, NULL, isNoGenome);
+        else
+            {
+            char *subTdbType = nextWord(&subTdbOff);
+            boolean subTdbIsNoGenome = sameString(subTdbType, "noGenome");
+            if (!subTdbIsNoGenome)
+                subTdbIsNoGenome = sameString(subTdbType, "off") || sameString(subTdbType, "tbNoGenome");
+            acHashAddOneTable(acHash, subTdb->table, NULL, subTdbIsNoGenome);
+            }
+        }
     }
 return acHash;
 }
 
 static struct hash *getCachedAcHash(char *db)
 /* Returns a hash that maps table names to accessControl, creating it if necessary. */
 {
 static struct hash *dbToAcHash = NULL;
 if (dbToAcHash == NULL)
     dbToAcHash = hashNew(0);
 struct hash *acHash = hashFindVal(dbToAcHash, db);
 if (acHash == NULL)
     {
     acHash = accessControlInit(db);
     hashAdd(dbToAcHash, db, acHash);