fd526976ba5971d4bae14235cf2f735751a5e548
angie
  Wed May 15 14:26:41 2019 -0700
Adding doReSaveSession to streamline loading and saving a session in one CGI request, for converting old session trash paths and customTrash tables to userdata and customData.  refs #22440

diff --git src/hg/hgSession/hgSession.c src/hg/hgSession/hgSession.c
index c07a0d5..1532a6a 100644
--- src/hg/hgSession/hgSession.c
+++ src/hg/hgSession/hgSession.c
@@ -745,44 +745,34 @@
             }
         }
     if (tdb->visibility != tvHide)
         outIfNotPresent(cart, dy, tdb->track, tdb->visibility);
     }
 
 // Put a variable in the cart that says we put the default 
 // visibilities in it.
 if (dy)
     dyStringPrintf(dy,"&%s=on", CART_HAS_DEFAULT_VISIBILITY);
 else
     printf("%s on", CART_HAS_DEFAULT_VISIBILITY);
 }
 
 #define INITIAL_USE_COUNT 0
-char *doNewSession(char *userName)
-/* Save current settings in a new named session.
- * Return a message confirming what we did. */
-{
-if (userName == NULL)
-    return "Unable to save session -- please log in and try again.";
-struct dyString *dyMessage = dyStringNew(2048);
-char *sessionName = trimSpaces(cartString(cart, hgsNewSessionName));
-char *encSessionName = cgiEncodeFull(sessionName);
-boolean shareSession = cartBoolean(cart, hgsNewSessionShare);
-char *encUserName = cgiEncodeFull(userName);
-struct sqlConnection *conn = hConnectCentral();
-
-if (sqlTableExists(conn, namedSessionTable))
+static int saveCartAsSession(struct sqlConnection *conn, char *encUserName, char *encSessionName,
+                             boolean shareSession)
+/* Save all settings in cart, either adding a new session or overwriting an existing session.
+ * Return useCount so that the caller can distinguish between adding and overWriting. */
 {
 struct sqlResult *sr = NULL;
 struct dyString *dy = dyStringNew(16 * 1024);
 char **row;
 char *firstUse = "now()";
 int useCount = INITIAL_USE_COUNT;
 char firstUseBuf[32];
 
 /* If this session already existed, preserve its firstUse and useCount. */
 sqlDyStringPrintf(dy, "SELECT firstUse, useCount FROM %s "
                   "WHERE userName = '%s' AND sessionName = '%s';",
                   namedSessionTable, encUserName, encSessionName);
 sr = sqlGetResult(conn, dy->string);
 if ((row = sqlNextRow(sr)) != NULL)
     {
@@ -813,31 +803,49 @@
 cartEncodeState(cart, encoded);
 
 // Now add all the default visibilities to output.
 outDefaultTracks(cart, encoded);
 
 sqlDyAppendEscaped(dy, encoded->string);
 dyStringFree(&encoded);
 dyStringAppend(dy, "', ");
 dyStringPrintf(dy, "%d, ", (shareSession ? 1 : 0));
 dyStringPrintf(dy, "%s, now(), %d, '');", firstUse, useCount);
 sqlUpdate(conn, dy->string);
 dyStringFree(&dy);
 
 /* Prevent modification of custom track collections just saved to namedSessionDb: */
 cartCopyCustomComposites(cart);
+return useCount;
+}
 
+char *doNewSession(char *userName)
+/* Save current settings in a new named session.
+ * Return a message confirming what we did. */
+{
+if (userName == NULL)
+    return "Unable to save session -- please log in and try again.";
+struct dyString *dyMessage = dyStringNew(2048);
+char *sessionName = trimSpaces(cartString(cart, hgsNewSessionName));
+char *encSessionName = cgiEncodeFull(sessionName);
+boolean shareSession = cartBoolean(cart, hgsNewSessionShare);
+char *encUserName = cgiEncodeFull(userName);
+struct sqlConnection *conn = hConnectCentral();
+
+if (sqlTableExists(conn, namedSessionTable))
+    {
+    int useCount = saveCartAsSession(conn, encUserName, encSessionName, shareSession);
     if (useCount > INITIAL_USE_COUNT)
 	dyStringPrintf(dyMessage,
 	  "Overwrote the contents of session <B>%s</B> "
 	  "(that %s be shared with other users).  "
 	  "%s %s",
 	  htmlEncode(sessionName), (shareSession ? "may" : "may not"),
 	  getSessionLink(encUserName, encSessionName),
 	  getSessionEmailLink(encUserName, encSessionName));
     else
 	dyStringPrintf(dyMessage,
 	  "Added a new session <B>%s</B> that %s be shared with other users.  "
 	  "%s %s",
 	  htmlEncode(sessionName), (shareSession ? "may" : "may not"),
 	  getSessionLink(encUserName, encSessionName),
 	  getSessionEmailLink(encUserName, encSessionName));
@@ -1522,30 +1530,80 @@
 			namedSessionTable, dyRa->string, encUserName, encSessionName);
 	sqlUpdate(conn, dyQuery->string);
 	dyStringPrintf(dyMessage, "Updated description of <B>%s</B>.\n", sessionName);
 	}
     }
 if (isEmpty(dyMessage->string))
     dyStringPrintf(dyMessage, "No changes to session <B>%s</B>.\n", sessionName);
 dyStringPrintf(dyMessage, "%s %s",
 	       getSessionLink(encUserName, encSessionName),
 	       getSessionEmailLink(encUserName, encSessionName));
 if (shared)
     printShareMessage(dyMessage, encUserName, encSessionName, FALSE);
 return dyStringCannibalize(&dyMessage);
 }
 
+static boolean isSessionShared(struct sqlConnection *conn, char *encUserName, char *encSessionName)
+/* Return the value of 'shared' from the namedSessionDb row for user & session;
+ * errAbort if there is no such session. */
+{
+char query[2048];
+sqlSafef(query, sizeof(query), "select shared from %s where userName='%s' and sessionName = '%s';",
+         namedSessionTable, encUserName, encSessionName);
+char buf[256];
+char *sharedStr = sqlQuickQuery(conn, query, buf, sizeof buf);
+if (sharedStr == NULL)
+    errAbort("Unable to find session for userName='%s' and sessionName='%s'; no result from query '%s'",
+             encUserName, encSessionName, query);
+return atoi(sharedStr);
+}
+
+char *doReSaveSession(char *userName, char *actionVar)
+/* Load a session (which may have old trash and customTrash references) and re-save it
+ * so that customTrash tables will be moved to customData* databases and trash paths
+ * will be replaced with userdata (hg.conf sessionDataDir) paths.
+ * NOTE: this is not intended to be reachable by the UI; it is for a script to update
+ * old sessions to use the new sessionData locations. */
+{
+if (userName == NULL)
+    return "Unable to re-save session -- please log in and try again.";
+struct sqlConnection *conn = hConnectCentral();
+char *sessionName = cloneString(trimSpaces(cartString(cart, hgsNewSessionName)));
+char *encUserName = cgiEncodeFull(userName);
+char *encSessionName = cgiEncodeFull(sessionName);
+boolean shareSession = isSessionShared(conn, encUserName, encSessionName);
+cartLoadUserSession(conn, userName, sessionName, cart, NULL, actionVar);
+// Don't cartCopyCustomComposites because we're not going to make any track collection changes
+hubConnectLoadHubs(cart);
+cartHideDefaultTracks(cart);
+struct dyString *dyMessage = dyStringNew(1024);
+dyStringPrintf(dyMessage,
+               "Re-saved settings from user <B>%s</B>'s session <B>%s</B> "
+               "that %s be shared with others.  %s %s",
+	       userName, htmlEncode(sessionName), (shareSession ? "may" : "may not"),
+	       getSessionLink(userName, encSessionName),
+	       getSessionEmailLink(encUserName, encSessionName));
+cartCheckForCustomTracks(cart, dyMessage);
+int useCount = saveCartAsSession(conn, encUserName, encSessionName, shareSession);
+if (useCount <= INITIAL_USE_COUNT)
+    errAbort("Expected useCount of at least %d after re-saving session for "
+             "userName='%s', sessionName='%s', but got %d",
+             INITIAL_USE_COUNT+1, encUserName, encSessionName, useCount);
+hDisconnectCentral(&conn);
+return dyStringCannibalize(&dyMessage);
+}
+
 // ======================================
 
 void prepBackGroundCall(char **pBackgroundProgress, char *cleanPrefix)
 /* fix cart and save state */
 {
 *pBackgroundProgress = cloneString(cgiUsualString("backgroundProgress", NULL)); 
 cartRemove(cart, "backgroundExec");
 cartRemove(cart, "backgroundProgress");
 cartRemovePrefix(cart, cleanPrefix);
 cartSaveState(cart);  // in case it crashes
 }
 
 void launchForeAndBackGround(char *operation)
 /* update cart, launch background and foreground */
 {
@@ -1718,30 +1776,35 @@
     doMainPage(userName, message);
     }
 else if (cartVarExists(cart, hgsOldSessionName))
     {
     char *message1 = doSessionChange(userName, cartString(cart, hgsOldSessionName));
     char *message2 = doUpdateSessions(userName);
     char *message = message2;
     if (!startsWith("No changes to session", message1))
 	{
 	size_t len = (sizeof message1[0]) * (strlen(message1) + strlen(message2) + 1);
 	message = needMem(len);
 	safef(message, len, "%s%s", message1, message2);
 	}
     doMainPage(userName, message);
     }
+else if (cartVarExists(cart, hgsDoReSaveSession))
+    {
+    char *message = doReSaveSession(userName, hgsDoReSaveSession);
+    printf("\n%s\n\n", message);
+    }
 else
     {
     char *message = doUpdateSessions(userName);
     doMainPage(userName, message);
     }
 
 cleanHgSessionFromCart(cart);
 /* Save the cart state: */
 cartCheckout(&cart);
 }
 
 int main(int argc, char *argv[])
 /* Process command line. */
 {
 long enteredMainTime = clock1000();