f4811acb1836d4a91ab6d2189aff8f1d7a438d1b
chmalee
  Tue Feb 25 15:10:49 2025 -0800
Remove hubSpace hub from the cart when deleting a hub.txt, refs #31058

diff --git src/hg/lib/userdata.c src/hg/lib/userdata.c
index 78f78bc1fba..037fad2c074 100644
--- src/hg/lib/userdata.c
+++ src/hg/lib/userdata.c
@@ -92,30 +92,41 @@
 /* Return a web accesible path to the userDataDir, this is different from the full path tusd uses */
 {
 char *retUrl = NULL;
 if (userName)
     {
     char *encUserName = cgiEncode(userName);
     char *userPrefix = md5HexForString(encUserName);
     userPrefix[2] = '\0';
     struct dyString *userDirDy = dyStringNew(0);
     dyStringPrintf(userDirDy, "%s/%s/%s/", getHubSpaceUrl(), userPrefix, encUserName);
     retUrl = dyStringCannibalize(&userDirDy);
     }
 return retUrl;
 }
 
+char *urlForFile(char *userName, char *filePath)
+/* Return a web accessible URL to filePath */
+{
+char *webDataUrl = webDataDir(userName);
+if (webDataUrl)
+    {
+    return catTwoStrings(webDataUrl, filePath);
+    }
+return NULL;
+}
+
 char *prefixUserFile(char *userName, char *fname, char *parentDir)
 /* Allocate a new string that contains the full per-user path to fname. return NULL if
  * we cannot construct a full path because of a realpath(3) failure.
  * parentDir is optional and will go in between the per-user dir and the fname */
 {
 char *pathPrefix = getDataDir(userName);
 char *path = NULL;
 if (pathPrefix)
     {
     if (parentDir)
         {
         struct dyString *ret = dyStringCreate("%s%s%s%s", pathPrefix, parentDir, lastChar(parentDir) == '/' ? "" : "/", fname);
         path = dyStringCannibalize(&ret);
         }
     else