7b7bb68187bb42ead29a9a3b26a950205820c9ae
chmalee
  Wed Nov 20 15:54:48 2024 -0800
Make up to 25 rows show by default, make the table scroll down if it's more than 600 pixels, make the table collapse when there are less than 600 pixels height needed.

Remove the 'Action' title, remove the delete button from each row, make the checkboxes select files, on checkbox select populate an info section about how many files have been selected and give the option to view or delete them

Start of reworking the delete button to delete a list of files. The backend still needs to be smarter about creating the locations of files

Put some place holder text where the selected file information would appear so the page doesn't jump around

Start of work on back end for removing files. Changed the json returned for listing the files to list the full path to the file to make the requests to delete a file easier. Still need to decide on encoding vs decoding of the parent dirs during uploads

diff --git src/hg/lib/userdata.c src/hg/lib/userdata.c
index fdb9445..041d684 100644
--- src/hg/lib/userdata.c
+++ src/hg/lib/userdata.c
@@ -47,58 +47,80 @@
 if (userDataBaseDir[0] != '/')
     errAbort("config setting userDataDir must be an absolute path (starting with '/')");
 
 char *encUserName = cgiEncode(userName);
 char *userPrefix = md5HexForString(encUserName);
 userPrefix[2] = '\0';
 
 struct dyString *newDataDir = dyStringNew(0);
 dyStringPrintf(newDataDir, "%s/%s/%s/", 
     userDataBaseDir, userPrefix, encUserName);
 
 fprintf(stderr, "userDataDir = '%s'\n", newDataDir->string);
 return dyStringCannibalize(&newDataDir);
 }
 
+char *stripDataDir(char *fname, char *userName)
+/* Strips the getDataDir(userName) off of fname */
+{
+char *dataDir = getDataDir(userName);
+int prefixSize = strlen(dataDir);
+if (startsWith(dataDir, fname))
+    {
+    char *ret = fname + prefixSize;
+    return ret;
+    }
+return NULL;
+}
+
 char *getHubDataDir(char *userName, char *hub)
 {
 char *dataDir = getDataDir(userName);
 return catTwoStrings(dataDir, hub);
 }
 
 char *webDataDir(char *userName)
 /* 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/", HUB_SPACE_URL, userPrefix, encUserName);
     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 *prefixUserFile(char *userName, char *fname, char *parentDir)
+/* Allocate a new string that contains the full per-user path to fname, NULL otherwise.
+ * parentDir is optional and will go in between the per-user dir and the fname */
 {
 char *pathPrefix = getDataDir(userName);
 if (pathPrefix)
+    {
+    if (parentDir)
+        {
+        struct dyString *ret = dyStringCreate("%s%s%s%s", pathPrefix, parentDir, lastChar(parentDir) == '/' ? "" : "/", fname);
+        return dyStringCannibalize(&ret);
+        }
+    else
         return catTwoStrings(pathPrefix, fname);
+    }
 else
     return NULL;
 }
 
 void addHubSpaceRowForFile(struct hubSpace *row)
 /* We created a file for a user, now add an entry to the hubSpace table for it */
 {
 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 genome-www@soe.ucsc.edu  describing the exact steps you took just before you got this error");
     }
 hubSpaceSaveToDb(conn, row, "hubSpace", 0);
@@ -233,93 +255,100 @@
 row->lastModified = sqlUnixTimeToDate(&lastModTime, TRUE);
 row->db = db;
 row->location = path;
 row->md5sum = md5HexForFile(hubFileName);
 fprintf(stderr, "making parent dir rows\n");
 fflush(stderr);
 makeParentDirRows(userName, lastModTime, db, parentDir);
 row->parentDir = hubName;
 struct dyString *parentsPath = dyStringCreate("%s%s", getDataDir(userName), parentDir);
 fprintf(stderr, "parentDir of hub.txt: '%s'\n", parentsPath->string);
 fflush(stderr);
 if (!checkHubSpaceRowExists(row))
     addHubSpaceRowForFile(row);
 }
 
-static void deleteHubSpaceRow(char *fname)
+static void deleteHubSpaceRow(char *fname, char *userName)
 /* 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);
+struct dyString *deleteQuery = sqlDyStringCreate("delete from hubSpace where location='%s' and userName='%s'", fname, userName);
 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))
     return;
 if (fileExists(fname))
     {
     // delete the actual file
     mustRemove(fname);
     // delete the table row
-    deleteHubSpaceRow(fname);
+    deleteHubSpaceRow(fname, userName);
     }
 }
 
 void removeHubForUser(char *path, char *userName)
 /* Remove a hub directory for this user (and all files in the directory), if it exists */
 {
 if (!startsWith(getDataDir(userName), path))
     return;
 if (isDirectory(path))
     {
     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);
+    deleteHubSpaceRow(path, userName);
     }
 }
 
 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);
 }
 
+char *findParentDirs(char *parentDir, char *userName, char *fname)
+/* For a given file with parentDir, go up the tree and find the full path back to
+ * the rootmost parentDir */
+{
+return NULL;
+}
+
 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 */
 {