bbe2055111b0bababdc240a64233b994f6b5de91 chmalee Tue Mar 4 11:13:56 2025 -0800 Bump up DataTables javascript library versions to fix layout bug when initializing a table but not displaying it yet, like we do in the hub upload tab on hgHubConnect, refs #31058 diff --git src/hg/hgHubConnect/trackHubWizard.c src/hg/hgHubConnect/trackHubWizard.c index 316199d6975..bd1eb5d2176 100644 --- src/hg/hgHubConnect/trackHubWizard.c +++ src/hg/hgHubConnect/trackHubWizard.c @@ -1,257 +1,257 @@ /* trackHubWizard -- a user interface for creating a track hubs configuration files */ /* Copyright (C) 2019 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 "hdb.h" #include "hgConfig.h" #include "md5.h" #include "trashDir.h" #include "hgHubConnect.h" #include "jsHelper.h" #include "web.h" #include "wikiLink.h" #include "customTrack.h" #include "userdata.h" #include "jsonWrite.h" #include "cartJson.h" #include "hubSpace.h" #include "hubSpaceKeys.h" #include "hubConnect.h" #include "trackHub.h" #include "htmshell.h" void removeOneFile(char *userName, char *cgiFileName, char *fullPath, char *db, char *fileType) /* Remove one single file for userName */ { // prefixUserFile returns a canonicalized path, or NULL if the // canonicalized path does not begin with the hg.conf specified userDataDir // TODO: make the debug information from stderr go to stdout so the user // can know there is a mistake somewhere, and only print the debug // information in the event that the filename actually begins with the // userDataDir so we don't tell hackers what files do and do not exist char *fileName = prefixUserFile(userName, fullPath, NULL); if (fileName) { if (fileExists(fileName)) { fprintf(stderr, "deleting file: '%s'\n", fileName); removeFileForUser(fileName, userName); fflush(stderr); } else { fprintf(stderr, "file '%s' does not exist\n", fileName); fflush(stderr); } } } int pathDepth(char *path) { return countChars(path, '/'); } int sortByFullPathCmp(const void *va, const void *vb) /* Compare two fullPaths */ { struct jsonElement *a = (struct jsonElement *)(*(struct slRef **)va)->val; struct jsonElement *b = (struct jsonElement *)(*(struct slRef **)vb)->val; char *aFullpath = jsonStringField(a, "fullPath"); char *bFullpath = jsonStringField(b, "fullPath"); int aDepth = pathDepth(aFullpath); int bDepth = pathDepth(bFullpath); // ensure subdirectories order before their parents: if (aDepth != bDepth) return bDepth - aDepth; // if equal depth than lexicographic sort is fine return strcmp(jsonStringField(a,"fullPath"), jsonStringField(b, "fullPath")); } void sortByFullPath(struct jsonElement *listJson) { slSort(&(listJson->val.jeList), sortByFullPathCmp); } void doRemoveFile(struct cartJson *cj, struct hash *paramHash) /* Process the request to remove a file */ { char *userName = getUserName(); if (userName) { // our array of objects, each object represents a track file struct jsonElement *deleteJson = hashFindVal(paramHash, "fileList"); struct slRef *copy, *f, *fileList = deleteJson->val.jeList; struct jsonElement *dirListJsonEle = newJsonList(NULL); jsonWriteListStart(cj->jw, "deletedList"); for (f = fileList; f != NULL; ) { struct jsonElement *fileObj = (struct jsonElement *)f->val; char *fileName = jsonStringField(fileObj, "fileName"); char *fileType = jsonStringField(fileObj, "fileType"); char *db = jsonStringField(fileObj, "genome"); char *fullPath = jsonStringField(fileObj, "fullPath"); copy = f->next; if (sameString(fileType, "dir")) { f->next = NULL; jsonListAdd(dirListJsonEle, fileObj); } else { if (sameString(fileType, "hub.txt")) { // disconnect this hub from the cart if it exists char *hubUrl = urlForFile(userName, fullPath); char *hubId = hubNameFromUrl(hubUrl); if (hubId) { /* remove the cart variable */ hubId += 4; // skip past the hub_ part char buffer[1024]; safef(buffer, sizeof buffer, "hgHubConnect.hub.%s", hubId); cartRemove(cj->cart, buffer); } } removeOneFile(userName, fileName, fullPath, db, fileType); // write out the fullPath so the DataTable can remove the correct row: jsonWriteString(cj->jw, NULL, fullPath); } f = copy; } // now attempt to delete any requested directories, but don't die if they still have contents sortByFullPath(dirListJsonEle); struct slRef *dir = NULL; for (dir = dirListJsonEle->val.jeList; dir != NULL; dir = dir->next) { struct jsonElement *fileObj = (struct jsonElement *)dir->val; char *fileName = jsonStringField(fileObj, "fileName"); char *fileType = jsonStringField(fileObj, "fileType"); char *db = jsonStringField(fileObj, "genome"); char *fullPath = jsonStringField(fileObj, "fullPath"); removeOneFile(userName, fileName, fullPath, db, fileType); // write out the fullPath so the DataTable can remove the correct row: jsonWriteString(cj->jw, NULL, fullPath); } jsonWriteListEnd(cj->jw); } } void doMoveFile(struct cartJson *cj, struct hash *paramHash) /* Move a file to a new hub */ { } static void outUiDataForUser(struct jsonWrite *jw) /* List out the currently stored files for the user as well as other data * needed to create the hubSpace table */ { char *userName = getUserName(); jsonWriteObjectStart(jw, "userFiles"); if (userName) { // the url for this user: jsonWriteString(jw, "userUrl", webDataDir(userName)); jsonWriteListStart(jw, "fileList"); struct hubSpace *file, *fileList = listFilesForUser(userName); for (file = fileList; file != NULL; file = file->next) { jsonWriteObjectStart(jw, NULL); jsonWriteString(jw, "fileName", file->fileName); jsonWriteNumber(jw, "fileSize", file->fileSize); jsonWriteString(jw, "fileType", file->fileType); jsonWriteString(jw, "parentDir", file->parentDir); jsonWriteString(jw, "genome", file->db); jsonWriteString(jw, "lastModified", file->lastModified); jsonWriteString(jw, "uploadTime", file->creationTime); jsonWriteString(jw, "fullPath", stripDataDir(file->location, userName)); jsonWriteString(jw, "md5sum", file->md5sum); jsonWriteObjectEnd(jw); } jsonWriteListEnd(jw); } jsonWriteBoolean(jw, "isLoggedIn", getUserName() ? TRUE : FALSE); jsonWriteString(jw, "hubNameDefault", defaultHubNameForUser(getUserName())); // if the user is not logged, the 0 for the quota is ignored jsonWriteNumber(jw, "userQuota", getUserName() ? checkUserQuota(getUserName()) : 0); jsonWriteNumber(jw, "maxQuota", getUserName() ? getMaxUserQuota(getUserName()) : HUB_SPACE_DEFAULT_QUOTA); jsonWriteObjectEnd(jw); } void getHubSpaceUIState(struct cartJson *cj, struct hash *paramHash) /* Get all the data we need to make a users hubSpace UI table. The cartJson library * deals with printing the json */ { outUiDataForUser(cj->jw); } void doTrackHubWizard(char *database) /* Offer an upload form so users can upload all their hub files */ { jsIncludeFile("utils.js", NULL); jsIncludeFile("ajax.js", NULL); jsIncludeFile("lodash.3.10.0.compat.min.js", NULL); jsIncludeFile("cart.js", NULL); puts("<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css\">\n"); puts("<link rel=\"stylesheet\" type=\"text/css\" " - "href=\"https://cdn.datatables.net/2.1.3/css/dataTables.dataTables.min.css\">\n"); + "href=\"https://cdn.datatables.net/2.2.2/css/dataTables.dataTables.min.css\">\n"); puts("<script type=\"text/javascript\" " - "src=\"https://cdn.datatables.net/2.1.3/js/dataTables.min.js\"></script>"); + "src=\"https://cdn.datatables.net/2.2.2/js/dataTables.min.js\"></script>"); puts("<link rel=\"stylesheet\" type=\"text/css\" " - "href=\"https://cdn.datatables.net/buttons/3.1.1/css/buttons.dataTables.min.css\">\n"); + "href=\"https://cdn.datatables.net/buttons/3.2.2/css/buttons.dataTables.min.css\">\n"); puts("<script type=\"text/javascript\" " - "src=\"https://cdn.datatables.net/buttons/3.1.1/js/dataTables.buttons.min.js\"></script>"); + "src=\"https://cdn.datatables.net/buttons/3.2.2/js/dataTables.buttons.min.js\"></script>"); puts("<link rel=\"stylesheet\" type=\"text/css\" " - "href=\"https://cdn.datatables.net/select/2.1.0/css/select.dataTables.min.css\">\n"); + "href=\"https://cdn.datatables.net/select/3.0.0/css/select.dataTables.min.css\">\n"); puts("<script type=\"text/javascript\" " - "src=\"https://cdn.datatables.net/select/2.1.0/js/dataTables.select.min.js\"></script>"); + "src=\"https://cdn.datatables.net/select/3.0.0/js/dataTables.select.min.js\"></script>"); puts("<link href=\"https://releases.transloadit.com/uppy/v4.5.0/uppy.min.css\" rel=\"stylesheet\">"); puts("<script type=\"text/javascript\" src=\"https://releases.transloadit.com/uppy/v4.5.0/uppy.min.js\"></script>"); jsIncludeFile("hgMyData.js", NULL); // the skeleton HTML: webIncludeFile("inc/hgMyData.html"); webIncludeResourceFile("hgMyData.css"); // get the current files and vars stored for this user struct jsonWrite *jw = jsonWriteNew(); outUiDataForUser(jw); jsInlineF("\nvar uiData = {%s}\n", jw->dy->string); jsonWriteFree(&jw); jsInlineF("\nvar cartDb=\"%s %s\";\n", trackHubSkipHubName(hGenome(database)), database); jsInlineF("\nvar tusdEndpoint=\"%s\";\n", cfgOptionDefault("hubSpaceTusdEndpoint", NULL)); jsInline("$(document).ready(function() {\nhubCreate.init();\n})"); puts("</div>"); } void revokeApiKey(struct cartJson *cj, struct hash *paramHash) /* Remove any api keys for the user */ { char *userName = getUserName(); struct sqlConnection *conn = hConnectCentral(); struct dyString *query = sqlDyStringCreate("delete from %s where userName='%s'", HUBSPACE_AUTH_TABLE, userName); sqlUpdate(conn, dyStringCannibalize(&query)); hDisconnectCentral(&conn); jsonWriteString(cj->jw, "revoke", "true"); } void generateApiKey(struct cartJson *cj, struct hash *paramHash) /* Make a random (but not crypto-secure api key for use of hubtools to upload to hubspace */ { char *userName = getUserName(); if (!userName) { jsonWriteString(cj->jw, "error", "generateApiKey: not logged in"); return; } char *apiKey = makeRandomKey(256); // just needs some arbitrary length // save this key to the database for this user, the 'on duplicate' part automatically revokes old keys struct sqlConnection *conn = hConnectCentral(); struct dyString *query = sqlDyStringCreate("insert into %s values ('%s', '%s') on duplicate key update apiKey='%s'", HUBSPACE_AUTH_TABLE, userName, apiKey, apiKey); sqlUpdate(conn, dyStringCannibalize(&query)); jsonWriteString(cj->jw, "apiKey", apiKey); hDisconnectCentral(&conn); }