dcabcf3e37e0b1e3c71b6a98358c1fb844ca3b8a
braney
  Tue Apr 22 12:26:11 2025 -0700
sessions save a copy of the quickLift hub.

diff --git src/hg/lib/sessionData.c src/hg/lib/sessionData.c
index 9bdaca2b99f..b0ebd403aa4 100644
--- src/hg/lib/sessionData.c
+++ src/hg/lib/sessionData.c
@@ -1,30 +1,31 @@
 /* sessionData - functions for moving user data out of trash into permanent storage
  *
  * Copyright (C) 2019-2024 The Regents of the University of California
  * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */
 
 #include "common.h"
 #include "cart.h"
 #include "cheapcgi.h"
 #include "customComposite.h"
 #include "customTrack.h"
 #include "hdb.h"
 #include "hgConfig.h"
 #include "md5.h"
 #include "trashDir.h"
 #include "sessionData.h"
+#include "quickLift.h"
 
 INLINE boolean isTrashPath(char *path)
 /* Return TRUE if path starts with trashDir. */
 {
 return startsWith(trashDir(), path);
 }
 
 static char *sessionDataPathFromTrash(char *trashPath, char *sessionDir)
 /* Make a new path from a trash path -- replace "../trash" with safe location. */
 {
 if (!isTrashPath(trashPath))
     errAbort("sessionDataPathFromTrash: input is non-trash path '%s'", trashPath);
 return replaceChars(trashPath, trashDir(), sessionDir);
 }
 
@@ -435,34 +436,34 @@
     {
     if (sessionDataDir[0] != '/')
         errAbort("config setting sessionDataDir must be an absolute path (starting with '/')");
     char *userHash = md5HexForString(encUserName);
     userHash[2] = '\0';
     char *sessionHash = md5HexForString(encSessionName);
     sessionHash[8] = '\0';
     struct dyString *dy = dyStringCreate("%s/%s/%s/%s",
                                          sessionDataDir, userHash, encUserName, sessionHash);
     dir = dyStringCannibalize(&dy);
     freeMem(sessionHash);
     }
 return dir;
 }
 
-INLINE boolean cartVarIsCustomComposite(char *cartVar)
-/* Return TRUE if cartVar starts with "customComposite-". */
+INLINE boolean cartVarIsLocalHub(char *cartVar)
+/* Return TRUE if cartVar starts with "customComposite-" or "hubQuickLift-". */
 {
-return startsWith(customCompositeCartName "-", cartVar);
+return startsWith(quickLiftCartName "-", cartVar) || startsWith(customCompositeCartName "-", cartVar);
 }
 
 static char *dayOfMonthString()
 /* Return a two-character string with the current day of the month [01..31].  Do not free.
  * (Yeah, not [0..30]!  See man 3 localtime.) */
 {
 static char dayString[16];
 time_t now = time(NULL);
 struct tm *tm = localtime(&now);
 safef(dayString, sizeof dayString, "%02u", tm->tm_mday);
 return dayString;
 }
 
 void sessionDataSaveSession(struct cart *cart, char *encUserName, char *encSessionName,
                             char *dbSuffix)
@@ -471,38 +472,38 @@
  * and update cart to point to the new locations. */
 {
 char *sessionDataDbPrefix = cfgOption("sessionDataDbPrefix");
 char *sessionDataDir = cfgOption("sessionDataDir");
 // Use (URL-encoded) userName and sessionName to make directory hierarchy under sessionDataDir
 char *sessionDir = sessionDirFromNames(sessionDataDir, encUserName, encSessionName);
 if (isNotEmpty(sessionDataDbPrefix) || isNotEmpty(sessionDir))
     {
     if (isNotEmpty(sessionDataDbPrefix) && dbSuffix == NULL)
         dbSuffix = dayOfMonthString();
     struct slPair *allVars = cartVarsLike(cart, "*");
     struct slPair *var;
     for (var = allVars;  var != NULL;  var = var->next)
         {
         if (startsWith(CT_FILE_VAR_PREFIX, var->name) ||
-            cartVarIsCustomComposite(var->name))
+            cartVarIsLocalHub(var->name) )
             {
             // val is file that contains references to trash files and customTrash db tables;
             // replace with new file containing references to saved files and tables.
             char *oldTrackFile = cloneString(var->val);
             char *newTrackFile = saveTrackFile(cart, var->name, var->val,
                                                sessionDataDbPrefix, dbSuffix, sessionDir);
-            if (newTrackFile && cartVarIsCustomComposite(var->name))
+            if (newTrackFile && cartVarIsLocalHub(var->name))
                 cartReplaceHubVars(cart, var->name, oldTrackFile, newTrackFile);
             freeMem(oldTrackFile);
             freeMem(newTrackFile);
             }
         else
             {
             // Regular cart var; save trash paths (possibly encoded) in value, if any are found.
             char *newVal = cloneString(var->val);
             saveTrashPaths(&newVal, sessionDir, FALSE);
             saveTrashPaths(&newVal, sessionDir, TRUE);
             // If the variable would end up with an empty value, leave the old deleted trash file
             // name in place because the CGIs know how to deal with that but may error out if the
             // value is just empty.
             if (newVal != var->val && isNotEmpty(skipLeadingSpaces(newVal)) &&
                 differentString(newVal, var->val))