2f0d3fa3d2bcbf3e23e834ca68565c470f73939d
chmalee
  Mon Oct 21 12:32:08 2024 -0700
Back end for auto-generating a hub with every user upload done

diff --git src/hg/lib/userdata.c src/hg/lib/userdata.c
index 07438a7..dea277b 100644
--- src/hg/lib/userdata.c
+++ src/hg/lib/userdata.c
@@ -79,62 +79,105 @@
     retUrl = dyStringCannibalize(&userDirDy);
     }
 return retUrl;
 }
 
 char *prefixUserFile(char *userName, char *fname)
 /* Allocate a new string that contains the full per-user path to fname, NULL otherwise */
 {
 char *pathPrefix = getDataDir(userName);
 if (pathPrefix)
     return catTwoStrings(pathPrefix, fname);
 else
     return NULL;
 }
 
-void addNewFileForUser(char *userName, char *fileName, long long fileSize, char *fileType,
-        time_t lastModified, char *hubName, char *db, char *location)
+void addHubSpaceRowForFile(struct hubSpace *row)
 /* We created a file for a user, now add an entry to the hubSpace table for it */
 {
-struct hubSpace *row = NULL;
-AllocVar(row);
-row->userName = userName;
-row->fileName = fileName;
-row->fileSize = fileSize;
-row->fileType = fileType;
-row->creationTime = NULL; // automatically handled by mysql
-row->lastModified = sqlUnixTimeToDate(&lastModified, TRUE);
-row->hubNameList = hubName;
-row->db = db;
-row->location = location;
-row->md5sum = md5HexForFile(row->location);
 struct sqlConnection *conn = hConnectCentral();
 
 // now write out row to hubSpace table
 if (!sqlTableExistsOnMain(conn, "hubSpace"))
     {
-    errAbort("No hubSpace MySQL table is present. Please send an email to us describing the steps you took just before you got this error");
+    errAbort("No hubSpace MySQL table is present. Please send an email to genome-www@soe.ucsc.edu  describing the exact steps you took just before you got this error");
     }
-struct dyString *sqlUpdateStmt = dyStringNew(0);
-sqlDyStringPrintf(sqlUpdateStmt, "insert into hubSpace values ('%s', '%s', %llu, "
-        "'%s', NULL, '%s', '', '%s', '%s', '%s')",
-        row->userName, row->fileName, row->fileSize, row->fileType,
-        row->lastModified, row->db, row->location, row->md5sum);
-fprintf(stderr, "%s\n", sqlUpdateStmt->string);
-fflush(stderr);
-sqlUpdate(conn, sqlUpdateStmt->string);
-hubSpaceFree(&row);
+hubSpaceSaveToDb(conn, row, "hubSpace", 0);
+}
+
+char *writeHubText(char *path, char *userName, char *encodedHubName, char *hubName, char *db)
+/* Create a hub.txt file, optionally creating the directory holding it. For convenience, return
+ * the file name of the created hub, which can be freed. */
+{
+int oldUmask = 00;
+oldUmask = umask(0);
+makeDirsOnPath(path);
+// restore umask
+umask(oldUmask);
+// now make the hub.txt with some basic information
+char *hubFile = catTwoStrings(path, "/hub.txt");
+FILE *f = mustOpen(hubFile, "w");
+//fprintf(stderr, "would write \"hub %s\nemail %s\nshortLabel %s\nlongLabel %s\nuseOneFile on\n\ngenome %s\n\n\" to %s", hubName, emailForUserName(userName), hubName, hubName, db, hubFile);
+fprintf(f, "hub %s\n"
+    "email %s\n"
+    "shortLabel %s\n"
+    "longLabel %s\n"
+    "useOneFile on\n"
+    "\n"
+    "genome %s\n"
+    "\n",
+    encodedHubName, emailForUserName(userName), hubName, hubName, db);
+carefulClose(&f);
+return hubFile;
+}
+
+char *createNewTempHubForUpload(char *requestId, char *userName, char *db, char *trackFileName, char *trackType)
+/* Creates a hub.txt for this upload with a random hub name. Returns the full path to the hub
+ * for convenience. */
+{
+char *encodedHubName = cgiEncodeFull(requestId);
+char *path = prefixUserFile(userName, encodedHubName);
+char *hubFileName = writeHubText(path, userName, encodedHubName, requestId, db);
+char *encodedTrack = cgiEncodeFull(trackFileName);
+struct dyString *trackFilePath = dyStringCreate("../%s", encodedTrack);
+FILE *f = mustOpen(hubFileName, "a");
+fprintf(f, "track %s\n"
+    "bigDataUrl %s\n"
+    "type %s\n"
+    "shortLabel %s\n"
+    "longLabel %s\n"
+    "\n",
+    encodedTrack, dyStringCannibalize(&trackFilePath),
+    trackType, trackFileName, trackFileName);
+carefulClose(&f);
+
+// we should update the mysql table now with a record of the hub.txt
+struct hubSpace *row = NULL;
+AllocVar(row);
+row->userName = userName;
+row->fileName = hubFileName;
+row->fileSize = fileSize(hubFileName);
+row->fileType = "hub";
+row->creationTime = NULL;
+time_t lastModTime = fileModTime(hubFileName);
+row->lastModified = sqlUnixTimeToDate(&lastModTime, TRUE);
+row->hubNameList = "";
+row->db = db;
+row->location = path;
+row->md5sum = md5HexForFile(hubFileName);
+addHubSpaceRowForFile(row);
+return encodedHubName;
 }
 
 static void deleteHubSpaceRow(char *fname)
 /* Deletes a row from the hubspace table for a given fname */
 {
 struct sqlConnection *conn = hConnectCentral();
 struct dyString *deleteQuery = sqlDyStringCreate("delete from hubSpace where location='%s'", fname);
 sqlUpdate(conn, dyStringCannibalize(&deleteQuery));
 }
 
 void removeFileForUser(char *fname, char *userName)
 /* Remove a file for this user if it exists */
 {
 // The file to remove must be prefixed by the hg.conf userDataDir
 if (!startsWith(getDataDir(userName), fname))
@@ -158,59 +201,84 @@
     struct fileInfo *f, *flist = listDirX(path, NULL, TRUE);
     for (f = flist; f != NULL; f = f->next)
         mustRemove(f->name);
     // now we have deleted all the files in the dir we can safely rmdir
     mustRemove(path);
     deleteHubSpaceRow(path);
     }
 }
 
 void uploadTrack()
 /* Saves a new track to the persistent storage for this user */
 {
 //char *userName = getUserName();
 }
 
+static time_t getFileListLatestTime(struct userFiles *userFiles)
+/* Return the greatest last access time of the files in userFiles->fileList */
+{
+if (!userFiles->fileList)
+    errAbort("no files in userFiles->fileList");
+time_t modTime = 0;
+struct fileInfo *f;
+for (f = userFiles->fileList; f != NULL; f = f->next)
+    {
+    if (f->lastAccess > modTime)
+        {
+        modTime = f->lastAccess;
+        }
+    }
+return modTime;
+}
+
+time_t getHubLatestTime(struct userHubs *hub)
+/* Return the latest access time of the files in a hub */
+{
+// NOTE: every hub is guaranteed to have at least one file
+return getFileListLatestTime(hub->fileList);
+}
+
 struct userFiles *listFilesForUserHub(char *userName, char *hubName)
 /* Get all the files for a particular hub for a particular user */
 {
 struct userFiles *userListing;
 AllocVar(userListing);
 char *path = getHubDataDir(userName, hubName);
 struct fileInfo *fiList = listDirX(path,NULL,FALSE);
 userListing->userName = userName;
 userListing->fileList = fiList;
 return userListing;
 }
 
 struct userHubs *listHubsForUser(char *userName)
 /* Lists the directories for a particular user */
 {
 struct userHubs *userHubs = NULL;
 char *path = getDataDir(userName);
 struct fileInfo *fi, *fiList = listDirX(path,NULL,FALSE);
 for (fi = fiList; fi != NULL; fi = fi->next)
     {
     if (fi->isDir)
         {
         struct userHubs *hub;
         AllocVar(hub);
         hub->hubName = cloneString(fi->name);
         hub->userName = cloneString(userName);
         char hubPath[PATH_LEN];
         safef(hubPath, sizeof(hubPath), "%s%s", path, fi->name);
         struct userFiles *hubFileList = listFilesForUserHub(userName, hub->hubName);
+        hub->lastModified = getFileListLatestTime(hubFileList);
         hub->fileList = hubFileList;
         slAddHead(&userHubs, hub);
         }
     }
 return userHubs;
 }
 
 struct hubSpace *listFilesForUser(char *userName)
 /* Return the files the user has uploaded */
 {
 struct sqlConnection *conn = hConnectCentral();
 struct dyString *query = sqlDyStringCreate("select * from hubSpace where userName='%s' order by creationTime, fileName", userName);
 struct hubSpace *fileList = hubSpaceLoadByQuery(conn, dyStringCannibalize(&query));
 return fileList;
 }