d060b70a11099fb693b769c781796b6b577715fb
angie
  Fri Nov 1 12:47:25 2024 -0700
If sessionDataDir is in hg.conf, make a new UI option to request that the Auspice JSON output files don't expire after two days, using sessionDataDir/hgPhyloPlace/ for storage.

diff --git src/hg/hgPhyloPlace/phyloPlace.c src/hg/hgPhyloPlace/phyloPlace.c
index 589725b..1db8526 100644
--- src/hg/hgPhyloPlace/phyloPlace.c
+++ src/hg/hgPhyloPlace/phyloPlace.c
@@ -17,30 +17,31 @@
 #include "hubConnect.h"
 #include "hui.h"
 #include "iupac.h"
 #include "jsHelper.h"
 #include "linefile.h"
 #include "mmHash.h"
 #include "obscure.h"
 #include "parsimonyProto.h"
 #include "phyloPlace.h"
 #include "phyloTree.h"
 #include "pipeline.h"
 #include "psl.h"
 #include "pthreadWrap.h"
 #include "ra.h"
 #include "regexHelper.h"
+#include "sessionData.h"
 #include "trackHub.h"
 #include "trashDir.h"
 #include "vcf.h"
 
 // Globals:
 static boolean measureTiming = FALSE;
 
 // Parameter constants:
 int maxGenotypes = 1000;        // Upper limit on number of samples user can upload at once.
 boolean showParsimonyScore = FALSE;
 int minSamplesForOwnTree = 3;  // If user uploads at least this many samples, show tree for them.
 char *leftLabelWidthForLongNames = "55";// Leave plenty of room for tree and long virus strain names
 
 
 char *phyloPlaceOrgSetting(char *org, char *settingName)
@@ -3290,30 +3291,43 @@
 
 static struct phyloTree *uploadedSamplesTree(char *singleSubtreeFile, struct slName *sampleIds)
 /* If the user uploaded enough samples to make a meaningful tree, then read in singleSubtreeFile
  * and prune all nodes that have no leaf descendants in sampleIds to get the tree of only the
  * uploaded samples. */
 {
 struct phyloTree *tree = NULL;
 if (slCount(sampleIds) >= minSamplesForOwnTree)
     {
     tree = phyloOpenTree(singleSubtreeFile);
     tree = phyloPruneToIds(tree, sampleIds);
     }
 return tree;
 }
 
+static void saveTrashFile(struct tempName *tn)
+/* If hg.conf specifies a long-term storage place for user data, then save tn there and make its
+ * original location a symbolic link to the new location.  Note: tn has "hgPhyloPlace" in the path
+ * already, and we're not associating these with hgLogin user IDs, so there's no need to build
+ * the path up past sessionDataDir (unlike in hgSession). */
+{
+char *sessionDataDir = cfgOption("sessionDataDir");
+if (isNotEmpty(sessionDataDir))
+    {
+    sessionDataSaveTrashFile(tn->forCgi, sessionDataDir);
+    }
+}
+
 static void phyloPlaceSamplesOneRef(struct lineFile *lf, char *db, char *org,
                                     char *refName, char *defaultProtobuf,
                                     boolean doMeasureTiming, int subtreeSize,
                                     struct trackLayout *tl, struct cart *cart, boolean *retSuccess)
 /* Given a lineFile that contains either FASTA, VCF, or a list of sequence names/ids:
  * If FASTA/VCF, then prepare VCF for usher; if that goes well then run usher, report results,
  * make custom track files and return the top-level custom track file.
  * If list of seq names/ids, then attempt to find their full names in the protobuf, run matUtils
  * to make subtrees, show subtree results, and return NULL.  Set retSuccess to TRUE if we were
  * able to get at least some results for the user's input. */
 {
 char *ctFile = NULL;
 measureTiming = doMeasureTiming;
 int startTime = clock1000();
 struct tempName *vcfTn = NULL;
@@ -3434,54 +3448,59 @@
     }
 
 if (results && results->singleSubtreeInfo)
     {
     if (retSuccess)
         *retSuccess = TRUE;
     puts("<p></p>");
     readQcThresholds(org, refName);
     int subtreeCount = slCount(results->subtreeInfoList);
     // Sort subtrees by number of user samples (largest first).
     slSort(&results->subtreeInfoList, subTreeInfoUserSampleCmp);
     // Make Nextstrain/auspice JSON file for each subtree.
     char *bigGenePredFile = phyloPlaceRefSettingPath(org, refName, "bigGenePredFile");
     struct geneInfo *geneInfoList = getGeneInfoList(bigGenePredFile, refGenome);
     struct seqWindow *gSeqWin = memSeqWindowNew(refGenome->name, refGenome->dna);
+    boolean subtreePersist = cartUsualBoolean(cart, "subtreePersist", FALSE);
     struct hash *sampleUrls = hashNew(0);
     struct tempName *jsonTns[subtreeCount];
     struct subtreeInfo *ti;
     int ix;
     for (ix = 0, ti = results->subtreeInfoList;  ti != NULL;  ti = ti->next, ix++)
         {
         AllocVar(jsonTns[ix]);
         char subtreeName[512];
         safef(subtreeName, sizeof(subtreeName), "subtreeAuspice%d", ix+1);
-        trashDirFile(jsonTns[ix], "ct", subtreeName, ".json");
+        trashDirFile(jsonTns[ix], "hgPhyloPlace", subtreeName, ".json");
         treeToAuspiceJson(ti, org, refName, geneInfoList, gSeqWin, sampleMetadata, NULL,
                           results->samplePlacements, jsonTns[ix]->forCgi, source);
+        if (subtreePersist)
+            saveTrashFile(jsonTns[ix]);
         // Add a link for every sample to this subtree, so the single-subtree JSON can
         // link to subtree JSONs
         char *subtreeUrl = nextstrainUrlFromTn(jsonTns[ix]);
         struct slName *sample;
         for (sample = ti->subtreeUserSampleIds;  sample != NULL;  sample = sample->next)
             hashAdd(sampleUrls, sample->name, subtreeUrl);
         }
     struct tempName *singleSubtreeJsonTn;
     AllocVar(singleSubtreeJsonTn);
-    trashDirFile(singleSubtreeJsonTn, "ct", "singleSubtreeAuspice", ".json");
+    trashDirFile(singleSubtreeJsonTn, "hgPhyloPlace", "singleSubtreeAuspice", ".json");
     treeToAuspiceJson(results->singleSubtreeInfo, org, refName, geneInfoList, gSeqWin, sampleMetadata,
                       sampleUrls, results->samplePlacements, singleSubtreeJsonTn->forCgi, source);
+    if (subtreePersist)
+        saveTrashFile(singleSubtreeJsonTn);
     reportTiming(&startTime, "make Auspice JSON");
     char *dbSetting = phyloPlaceRefSetting(org, refName, "db");
     if (dbSetting)
         db = connectIfHub(cart, dbSetting);
     boolean canDoCustomTracks = (!subtreesOnly &&
                                  (sameString(db, refName) || isNotEmpty(dbSetting)));
     if (canDoCustomTracks)
         // Form submits subtree custom tracks to hgTracks
         printf("<form action='%s' name='resultsForm_%s' method=%s>\n\n",
                hgTracksName(), db, cartUsualString(cart, "formMethod", "POST"));
 
     makeButtonRow(singleSubtreeJsonTn, jsonTns, results->subtreeInfoList, subtreeSize, isFasta,
                   canDoCustomTracks);
     printf("<p>If you have metadata you wish to display, click a 'view subtree in "
            "Nextstrain' button, and then you can drag on a CSV file to "