05094dabf3d005ab35a998ff225443fc4255611f galt Mon Feb 4 23:07:42 2019 -0800 Adding ability to backup and restore the cart and its custom tracks in hgSession. diff --git src/hg/hgSession/hgSession.c src/hg/hgSession/hgSession.c index 864a092..c15aecc 100644 --- src/hg/hgSession/hgSession.c +++ src/hg/hgSession/hgSession.c @@ -19,34 +19,38 @@ #include "linefile.h" #include "net.h" #include "textOut.h" #include "hCommon.h" #include "hui.h" #include "cart.h" #include "jsHelper.h" #include "web.h" #include "hdb.h" #include "ra.h" #include "wikiLink.h" #include "customTrack.h" #include "customFactory.h" #include "udc.h" #include "hgSession.h" -#include "hubConnect.h" #include "hgConfig.h" #include "sessionThumbnail.h" +#include "filePath.h" #include "obscure.h" +#include "trashDir.h" +#include "hubConnect.h" + +#include "trackHub.h" void usage() /* Explain usage and exit. */ { errAbort( "hgSession - Interface with wiki login and do session saving/loading.\n" "usage:\n" " hgSession \n" ); } /* Global variables. */ struct cart *cart; char *excludeVars[] = {"Submit", "submit", NULL}; struct slName *existingSessionNames = NULL; @@ -295,31 +299,32 @@ " \"order\":[1,'asc'],\n" " \"stateSave\":true,\n" " \"stateSaveCallback\": %s,\n" " \"stateLoadCallback\": %s\n" " });\n" "} );\n" "}\n" , jsDataTableStateSave(hgSessionPrefix), jsDataTableStateLoad(hgSessionPrefix, cart)); printf("

My Sessions

\n"); printf("
"); printf("\n"); printf(""); printf("" "" - "" + "" + "" "" "", cartSidUrlString(cart)); printf(""); printf("\n"); if (gotSettings) sqlSafef(query, sizeof(query), "SELECT sessionName, shared, firstUse, contents, settings from %s " "WHERE userName = '%s' ORDER BY sessionName;", namedSessionTable, encUserName); else sqlSafef(query, sizeof(query), "SELECT sessionName, shared, firstUse, contents from %s " "WHERE userName = '%s' ORDER BY sessionName;", namedSessionTable, encUserName); sr = sqlGetResult(conn, query); @@ -363,30 +368,31 @@ db = cloneStringZ(dbIdx, dbEnd-dbIdx); else db = cloneString(dbIdx); printf("%s\n"); printf("\n"); printf("\n"); printf("\n"); + +printf("\n"); + +char name[256]; +safef(name, sizeof name, "%s", hgsExtractUploadPrefix); + +printf(""); +printf(""); +printf(""); +printf(""); + +// check the file name, e.g. does it have the right name or extension? +char js[1024]; +safef(js, sizeof js, +"var control = document.getElementById('%s');" +"var files = control.files;" +"if ((files.length == 1) && (files[0].name.endsWith('.tar.gz')))" +" return true;" +"alert('Please choose the correct backup archive ending in .tar.gz');" +"return false;" +, name); + +jsOnEventById("click", "archiveUpload", js); + printf("
session name (click to load)created onassemblyview/edit 
details 
delete this 
session 
share with 
others? 
delete this 
session 
share with 
others? 
post in 
public listing?
send to
mail
", db); } else printf("n/a"); if (gotSettings) { safef(buf, sizeof(buf), "%s%s", hgsEditPrefix, encSessionName); cgiMakeButton(buf, "details"); } else printf("unavailable"); + printf(""); safef(buf, sizeof(buf), "%s%s", hgsDeletePrefix, encSessionName); char command[512]; safef(command, sizeof(command), confirmDeleteFormat, encSessionName); cgiMakeOnClickSubmitButton(command, buf, "delete"); printf(""); safef(buf, sizeof(buf), "%s%s", hgsSharePrefix, encSessionName); cgiMakeCheckBoxWithId(buf, shared>0, buf); jsOnEventById("change",buf,"console.log('new status' + this.checked); document.mainForm.submit();"); printf(""); safef(buf, sizeof(buf), "%s%s", hgsGalleryPrefix, encSessionName); cgiMakeCheckBoxFourWay(buf, inGallery, shared>0, buf, NULL, NULL); jsOnEventById("change", buf, "document.mainForm.submit();"); @@ -446,30 +452,55 @@ jsOnEventById("keypress", hgsLoadLocalFileName,"return noSubmitOnEnter(event);"); printf("  "); cgiMakeButton(hgsDoLoadLocal, "submit"); printf("
Use settings from a URL (http://..., ftp://...):" "\n"); cgiMakeOnKeypressTextVar(hgsLoadUrlName, cartUsualString(cart, hgsLoadUrlName, ""), 20, jsPressOnEnter(hgsDoLoadUrl)); printf("  "); cgiMakeButton(hgsDoLoadUrl, "submit"); printf("
Use settings including custom tracks in local backup archive file (.tar.gz):", name, name); +printf("  
\n"); printf("

\n"); } void showSavingOptions(char *userName) /* Show options for saving a new named session in our db or to a file. */ { printf("

Save Settings

\n"); printf("\n"); if (isNotEmpty(userName)) { printf("\n" "\n"); printf("\n"); printf("\n"); + +printf("\n"); +printf(""); +printf("\n"); + +printf("\n"); printf("
Save current settings as named session:" "
   name:\n"); @@ -519,30 +550,40 @@ printf("file type returned: "); char *compressType = cartUsualString(cart, hgsSaveLocalFileCompress, textOutCompressNone); cgiMakeRadioButton(hgsSaveLocalFileCompress, textOutCompressNone, differentWord(textOutCompressGzip, compressType)); printf(" plain text  "); cgiMakeRadioButton(hgsSaveLocalFileCompress, textOutCompressGzip, sameWord(textOutCompressGzip, compressType)); printf(" gzip compressed (ignored if output file is blank)"); printf(""); printf(" "); cgiMakeButton(hgsDoSaveLocal, "submit"); printf("
(leave file blank to get output in " "browser window)
Save Full Session:
   "); +printf("backup settings including custom tracks to archive .tar.gz"); +printf(" "); +cgiMakeButton(hgsShowDownloadPrefix, "submit"); +printf("
\n"); } void showSessionControls(char *userName, boolean savedSessionsSupported, boolean webStarted) /* If userName is non-null, show sessions that belong to user and allow * saving of named sessions. * If savedSessionsSupported, allow import of named sessions. * Allow export/import of settings from file/URL. */ { char *formMethod = cartUsualString(cart, "formMethod", "POST"); if (webStarted) webNewSection("Session Management"); else @@ -675,30 +716,35 @@ void cleanHgSessionFromCart(struct cart *cart) /* Remove hgSession action variables that should not stay in the cart. */ { char varName[256]; safef(varName, sizeof(varName), "%s%s", cgiBooleanShadowPrefix(), hgsSharePrefix); cartRemovePrefix(cart, varName); cartRemovePrefix(cart, hgsSharePrefix); safef(varName, sizeof(varName), "%s%s", cgiBooleanShadowPrefix(), hgsGalleryPrefix); cartRemovePrefix(cart, varName); cartRemovePrefix(cart, hgsGalleryPrefix); cartRemovePrefix(cart, hgsLoadPrefix); cartRemovePrefix(cart, hgsEditPrefix); cartRemovePrefix(cart, hgsLoadLocalFileName); cartRemovePrefix(cart, hgsDeletePrefix); +cartRemovePrefix(cart, hgsShowDownloadPrefix); +cartRemovePrefix(cart, hgsMakeDownloadPrefix); +cartRemovePrefix(cart, hgsDoDownloadPrefix); +cartRemovePrefix(cart, hgsExtractUploadPrefix); +cartRemovePrefix(cart, hgsDoUploadPrefix); cartRemovePrefix(cart, hgsDo); cartRemove(cart, hgsOldSessionName); cartRemove(cart, hgsCancel); } static void outIfNotPresent(struct cart *cart, struct dyString *dy, char *track, int tdbVis) /* Output default trackDb visibility if it's not mentioned in the cart. */ { char *cartVis = cartOptionalString(cart, track); if (cartVis == NULL) { if (dy) dyStringPrintf(dy,"&%s=%s", track, hStringFromTv(tdbVis)); else printf("%s %s\n", track, hStringFromTv(tdbVis)); @@ -965,31 +1011,33 @@ "\n", sessionName, hgSessionName(), cartSessionVarName(cart), cartSessionId(cart), hgsOldSessionName, sessionName, hgsNewSessionName, hgsNewSessionName, 32, sessionName); jsOnEventById("change" , hgsNewSessionName, highlightAccChanges); jsOnEventById("keypress", hgsNewSessionName, highlightAccChanges); dyStringPrintf(dyMessage, "  " "  " "  " "   " "
\n", hgsLoadPrefix, encSessionName, hgsDeletePrefix, encSessionName, hgsDeletePrefix, encSessionName, - hgsDoSessionChange, hgsDoSessionChange, hgsCancel); + hgsDoSessionChange, hgsDoSessionChange, + hgsCancel); + char id[256]; safef(id, sizeof id, "%s%s", hgsDeletePrefix, encSessionName); jsOnEventByIdF("click", id, confirmDeleteFormat, encSessionName); dyStringPrintf(dyMessage, "Share with others? \n" "
\n", hgsSharePrefix, encSessionName, (shared>0 ? " CHECKED" : ""), cgiBooleanShadowPrefix(), hgsSharePrefix, encSessionName); jsOnEventByIdF("change", "detailsSharedCheckbox", "{%s %s}", highlightAccChanges, toggleGalleryDisable); jsOnEventByIdF("click" , "detailsSharedCheckbox", "{%s %s}", highlightAccChanges, toggleGalleryDisable); dyStringPrintf(dyMessage, "List in Public Sessions? %s.\n", sessionName, newName); sessionName = newName; encSessionName = encNewName; renamePrefixedCartVar(hgsEditPrefix , encOldSessionName, encNewName); renamePrefixedCartVar(hgsLoadPrefix , encOldSessionName, encNewName); renamePrefixedCartVar(hgsDeletePrefix , encOldSessionName, encNewName); + renamePrefixedCartVar(hgsShowDownloadPrefix , encOldSessionName, encNewName); + renamePrefixedCartVar(hgsMakeDownloadPrefix , encOldSessionName, encNewName); + renamePrefixedCartVar(hgsDoDownloadPrefix , encOldSessionName, encNewName); + renamePrefixedCartVar(hgsExtractUploadPrefix, encOldSessionName, encNewName); + renamePrefixedCartVar(hgsDoUploadPrefix , encOldSessionName, encNewName); if (shared >= 2) { thumbnailRemove(encUserName, encSessionName, conn); thumbnailAdd(encUserName, encNewName, conn, dyMessage); } } char sharedVarName[256]; char galleryVarName[256]; safef(sharedVarName, sizeof(sharedVarName), hgsSharePrefix "%s", encOldSessionName); safef(galleryVarName, sizeof(galleryVarName), hgsGalleryPrefix "%s", encOldSessionName); if (cgiBooleanDefined(sharedVarName) || cgiBooleanDefined(galleryVarName)) { int newShared = shared; if (cgiBooleanDefined(sharedVarName)) @@ -1499,45 +1552,262 @@ namedSessionTable, dyRa->string, encUserName, encSessionName); sqlUpdate(conn, dyQuery->string); dyStringPrintf(dyMessage, "Updated description of %s.\n", sessionName); } } if (isEmpty(dyMessage->string)) dyStringPrintf(dyMessage, "No changes to session %s.\n", sessionName); dyStringPrintf(dyMessage, "%s %s", getSessionLink(encUserName, encSessionName), getSessionEmailLink(encUserName, encSessionName)); if (shared) printShareMessage(dyMessage, encUserName, encSessionName, FALSE); 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 */ +{ +char cmd[1024]; +safef(cmd, sizeof cmd, "./hgSession backgroundExec=%s", operation); + +// allow child to see variables loaded from CGI. +// because CGI settings have not been saved back to the cart yet +cartSaveState(cart); + +char *workUrl = NULL; +// automatically adds hgsid +// automatically adds backGroundProgress=%s url.progress for separate channel +// Have to pass the userName manually since background exec will not get cookie, +// but we are no longer using userName which was needed with saved-sessions. +startBackgroundWork(cmd, &workUrl); + +htmlOpen("Background Status"); + +jsInlineF( + "setTimeout(function(){location = 'hgSession?backgroundStatus=%s&hgsid=%s';},2000);\n", + cgiEncode(workUrl), cartSessionId(cart)); +htmlClose(); +fflush(stdout); +} + +void passSubmittedBinaryAsTrashFile(struct hashEl *list) +/* fetch the binary file submitted in memory, + * and save it to temp trash location, + * saving the name in the cart. + * This is necessary to pass the file to the background process.*/ +{ +// List should have these two +// hgS_extractUpload_hub_9614_Anc11__binary +// hgS_extractUpload_hub_9614_Anc11__filename +// can have a third __filepath if crashes leaving in the cart. + +char *binaryParam = NULL; +struct hashEl *hel = NULL; +for (hel = list; hel; hel = hel->next) + { + if (endsWith(hel->name, "__binary")) + binaryParam = cloneString(hel->name); + } + +if (!binaryParam) + { + htmlOpen("No file selected"); + printf("Please choose a saved session custom tracks local backup archive file (.tar.gz) to upload"); + htmlClose(); + exit(0); + } + +char *binaryValue = cartOptionalString(cart, binaryParam); + +char *binInfo = cloneString(binaryValue); +char *words[2]; +char *mem; +unsigned long size; +chopByWhite(binInfo, words, ArraySize(words)); +mem = (char *)sqlUnsignedLong(words[0]); +size = sqlUnsignedLong(words[1]); + +struct tempName tn; +trashDirFile(&tn, "backGround", cartSessionId(cart), ".bin"); + +writeGulp(tn.forCgi, mem, size); + +// add new cart var with trash path +// hgS_extractUpload_hub_9614_Anc11__filepath +char *varName = replaceChars(binaryParam, "__binary", "__filepath"); +cartRemove(cart, varName); // just in case +cartSetString(cart, varName, tn.forCgi); // update the cart +} void hgSession() /* hgSession - Interface with wiki login and do session saving/loading. * Here we set up cart and some global variables, dispatch the command, * and put away the cart when it is done. */ { struct hash *oldVars = hashNew(10); /* Sometimes we output HTML and sometimes plain text; let each outputter * take care of headers instead of using a fixed cart*Shell(). */ cart = cartAndCookieNoContent(hUserCookie(), excludeVars, oldVars); char *userName = (loginSystemEnabled() || wikiLinkEnabled()) ? wikiLinkUserName() : NULL; -if (cartVarExists(cart, hgsDoMainPage) || cartVarExists(cart, hgsCancel)) +char *backgroundStatus = cloneString(cartUsualString(cart, "backgroundStatus", NULL)); + +if (backgroundStatus) + { + // clear backgroundStatus from the cart + cartRemove(cart, "backgroundStatus"); + /* Save cart variables. */ + cartSaveState(cart); + getBackgroundStatus(backgroundStatus); + exit(0); + } + +char *backgroundExec = cloneString(cgiUsualString("backgroundExec", NULL)); + + +struct hashEl *showDownloadList = cartFindPrefix(cart, hgsShowDownloadPrefix); +struct hashEl *makeDownloadList = cartFindPrefix(cart, hgsMakeDownloadPrefix); +struct hashEl *doDownloadList = cartFindPrefix(cart, hgsDoDownloadPrefix); +struct hashEl *extractUploadList = cartFindPrefix(cart, hgsExtractUploadPrefix); +struct hashEl *doUploadList = cartFindPrefix(cart, hgsDoUploadPrefix); + +// The form gets submitted but no filename for upload was chosen and submitted. +if (extractUploadList && sameString(hgsExtractUploadPrefix, extractUploadList->name)) + extractUploadList = NULL; // no filename was submitted. ignore. + +if (showDownloadList) + showDownloadSessionCtData(showDownloadList); +else if (makeDownloadList) + { + if (sameOk(backgroundExec,"makeDownloadSessionCtData")) + { + // only one, not a list. + struct hashEl *hel = makeDownloadList; + char *param1 = cloneString(hel->name); + + char *backgroundProgress = NULL; + prepBackGroundCall(&backgroundProgress, hgsMakeDownloadPrefix); + + makeDownloadSessionCtData(param1, backgroundProgress); + + exit(0); // cannot return + } + else + { + + launchForeAndBackGround("makeDownloadSessionCtData"); + + exit(0); + } + + } +else if (doDownloadList) + doDownloadSessionCtData(doDownloadList); +else if (extractUploadList) + { + if (sameOk(backgroundExec,"extractUploadSessionCtData")) + { + // only one, but becomes a list + // since there are multiple cart names with suffixes for handling binary submitted file. + //hgS_extractUpload___filepath + //hgS_extractUpload___binary + //hgS_extractUpload___filename + char *param1 = NULL; + char *param2 = NULL; + char *param3 = NULL; + struct hashEl *hel = NULL; + for (hel = extractUploadList; hel; hel = hel->next) + { + if (endsWith(hel->name, "__binary")) + param1 = cloneString(hel->name); + if (endsWith(hel->name, "__filename")) + param2 = cloneString(hel->name); + if (endsWith(hel->name, "__filepath")) + param3 = cloneString(hel->name); + } + if (!param1) + errAbort("missing __binary param"); + if (!param2) + errAbort("missing __filename param"); + if (!param3) + errAbort("missing __filepath param"); + + char *param1Value = cloneString(cartOptionalString(cart, param1)); + char *param2Value = cloneString(cartOptionalString(cart, param2)); + char *param3Value = cloneString(cartOptionalString(cart, param3)); + + char *backgroundProgress = NULL; + prepBackGroundCall(&backgroundProgress, hgsExtractUploadPrefix); + + extractUploadSessionCtData( + param1, param1Value, + param2, param2Value, + param3, param3Value, + backgroundProgress); + + exit(0); // cannot return + } + else + { + passSubmittedBinaryAsTrashFile(extractUploadList); + + launchForeAndBackGround("extractUploadSessionCtData"); + + exit(0); + } + + } +else if (doUploadList) + { + if (sameOk(backgroundExec,"doUploadSessionCtData")) + { + // only one, not a list. + struct hashEl *hel = doUploadList; + char *param1 = cloneString(hel->name); + + char *backgroundProgress = NULL; + prepBackGroundCall(&backgroundProgress, hgsDoUploadPrefix); + + doUploadSessionCtData(param1, backgroundProgress); + + exit(0); // cannot return + } + else + { + + launchForeAndBackGround("doUploadSessionCtData"); + + exit(0); + } + + } +else if (cartVarExists(cart, hgsDoMainPage) || cartVarExists(cart, hgsCancel)) doMainPage(userName, NULL); else if (cartVarExists(cart, hgsDoNewSession)) { char *message = doNewSession(userName); doMainPage(userName, message); } else if (cartVarExists(cart, hgsDoOtherUser)) { char *message = doOtherUser(hgsDoOtherUser); doMainPage(userName, message); } else if (cartVarExists(cart, hgsDoSaveLocal)) { doSaveLocal(); }