6411d5f0ae8b75f54dc71f28a6c0690a9d567895 braney Mon May 16 11:29:37 2011 -0700 make private (now unlisted) hubs use the same status table as the public hubs, no trash use diff --git src/hg/hgHubConnect/hgHubConnect.c src/hg/hgHubConnect/hgHubConnect.c index 1ce9eb7..56ab99c 100644 --- src/hg/hgHubConnect/hgHubConnect.c +++ src/hg/hgHubConnect/hgHubConnect.c @@ -5,366 +5,489 @@ #include "linefile.h" #include "errabort.h" #include "errCatch.h" #include "hCommon.h" #include "dystring.h" #include "jksql.h" #include "cheapcgi.h" #include "htmshell.h" #include "hdb.h" #include "hui.h" #include "cart.h" #include "dbDb.h" #include "web.h" #include "trackHub.h" #include "hubConnect.h" -#include "trashDir.h" +#include "dystring.h" #include "hPrint.h" -#define TEXT_ENTRY_ROWS 7 -#define TEXT_ENTRY_COLS 73 -#define CONFIG_ENTRY_ROWS 3 -#define SAVED_LINE_COUNT 50 - -#define HUB_CUSTOM_TEXT_ALT_VAR "hghub_customText" -#define HUB_CUSTOM_FILE_VAR "hghub.customFile" -#define HUB_UPDATED_ID "hghub_updatedId" - - - -#define hgHubDataText HUB_CUSTOM_TEXT_ALT_VAR -#define hgHubDataFile HUB_CUSTOM_FILE_VAR -#define hgHubUpdatedId HUB_UPDATED_ID +#define hgHubDataText "hgHub_customText" #define hgHub "hgHub_" /* prefix for all control variables */ #define hgHubDo hgHub "do_" /* prefix for all commands */ #define hgHubDoAdd hgHubDo "add" - +#define hgHubDoClear hgHubDo "clear" struct cart *cart; /* The user's ui state. */ struct hash *oldVars = NULL; static char *destUrl = "../cgi-bin/hgTracks"; static char *pageTitle = "Import Tracks from Data Hubs"; char *database = NULL; char *organism = NULL; -boolean nameInCommaList(char *name, char *commaList) +static boolean nameInCommaList(char *name, char *commaList) /* Return TRUE if name is in comma separated list. */ { if (commaList == NULL) return FALSE; int nameLen = strlen(name); for (;;) { char c = *commaList; if (c == 0) return FALSE; if (memcmp(name, commaList, nameLen) == 0) { c = commaList[nameLen]; if (c == 0 || c == ',') return TRUE; } commaList = strchr(commaList, ','); if (commaList == NULL) return FALSE; commaList += 1; } } -void hgHubConnectPrivate() -/* Put up the list of private hubs and other controls for the page. */ +static void hgHubConnectUnlisted() +/* Put up the list of unlisted hubs and other controls for the page. */ { -printf("<B>List of Private Hubs</B><BR>"); +printf("<B>Unlisted Hubs</B><BR>"); struct hubConnectStatus *hub, *hubList = hubConnectStatusListFromCart(cart); int count = 0; for(hub = hubList; hub; hub = hub->next) { - if (hub->id > 0) + /* if the hub is public, then don't list it here */ + if (!isHubUnlisted(hub)) continue; + if (count) webPrintLinkTableNewRow(); else webPrintLinkTableStart(); count++; if (isEmpty(hub->errorMessage)) { webPrintLinkCellStart(); char hubName[32]; - safef(hubName, sizeof(hubName), "%s%d", hgHubConnectHubVarPrefix, hub->id); + safef(hubName, sizeof(hubName), "%s%u", hgHubConnectHubVarPrefix, hub->id); cartMakeCheckBox(cart, hubName, FALSE); webPrintLinkCellEnd(); } else webPrintLinkCell("error"); webPrintLinkCell(hub->shortLabel); if (isEmpty(hub->errorMessage)) webPrintLinkCell(hub->longLabel); else webPrintLinkCell(hub->errorMessage); webPrintLinkCell(hub->hubUrl); } if (count) webPrintLinkTableEnd(); else - printf("No Private Track Hubs for this genome assembly<BR>"); + printf("No Unlisted Track Hubs for this genome assembly<BR>"); } static void makeNewHubButton() { printf("<FORM ACTION=\"%s\" METHOD=\"POST\" NAME=\"secondForm\">\n", "../cgi-bin/hgHubConnect"); cartSaveSession(cart); cgiMakeHiddenVar(hgHubDoAdd, "on"); -cgiMakeButton("add", "Add new private hub"); +cgiMakeButton("add", "Add new unlisted hub"); printf("</FORM>\n"); } static void makeGenomePrint() { getDbAndGenome(cart, &database, &organism, oldVars); printf("<B>genome:</B> %s <B>assembly:</B> %s ", organism, hFreezeDate(database)); } -void hgHubConnectPublic() -/* Put up the list of external hubs and other controls for the page. */ -{ -printf("<B>List of Public Hubs</B><BR>"); -struct sqlConnection *conn = hConnectCentral(); -char query[512]; -safef(query, sizeof(query), "select id,shortLabel,longLabel,errorMessage,hubUrl,dbList from %s", - hubConnectTableName); -struct sqlResult *sr = sqlGetResult(conn, query); -char **row; - -boolean gotAnyRows = FALSE; -while ((row = sqlNextRow(sr)) != NULL) - { - char *id = row[0], *shortLabel = row[1], *longLabel = row[2], *errorMessage = row[3], - *url = row[4], *dbList = row[5]; - if (nameInCommaList(database, dbList)) - { - if (gotAnyRows) - webPrintLinkTableNewRow(); - else - { - webPrintLinkTableStart(); - gotAnyRows = TRUE; - } - if (isEmpty(errorMessage)) - { - webPrintLinkCellStart(); - char hubName[32]; - safef(hubName, sizeof(hubName), "%s%s", hgHubConnectHubVarPrefix, id); - cartMakeCheckBox(cart, hubName, FALSE); - webPrintLinkCellEnd(); - } - else - webPrintLinkCell("error"); - webPrintLinkCell(shortLabel); - if (isEmpty(errorMessage)) - webPrintLinkCell(longLabel); - else - webPrintLinkCell(errorMessage); - webPrintLinkCell(url); - } - } -sqlFreeResult(&sr); -if (gotAnyRows) - webPrintLinkTableEnd(); -else - printf("No Track Hubs for this genome assembly"); -hDisconnectCentral(&conn); -} - static void addIntro() { printf("Enter URL to remote hub.<BR>\n"); } -void makeClearButton(char *field) -/* UI button that clears a text field */ -{ -char javascript[1024]; -safef(javascript, sizeof javascript, - "document.mainForm.%s.value = '';", field); -cgiMakeOnClickButton(javascript, " Clear "); -} - -void addPrivateHubForm(struct hubConnectStatus *hub, char *err) -/* display UI for adding private hubs by URL or pasting data */ +void addUnlistedHubForm(struct hubConnectStatus *hub, char *err) +/* display UI for adding unlisted hubs by URL */ { getDbAndGenome(cart, &database, &organism, oldVars); boolean gotClade = FALSE; boolean isUpdateForm = FALSE; if (hub) { isUpdateForm = TRUE; } else /* add form needs clade for assembly menu */ gotClade = hGotClade(); /* main form */ printf("<FORM ACTION=\"%s\" METHOD=\"%s\" " " ENCTYPE=\"multipart/form-data\" NAME=\"mainForm\">\n", "../cgi-bin/hgHubConnect", cartUsualString(cart, "formMethod", "POST")); cartSaveSession(cart); cgiMakeHiddenVar(hgHubConnectRemakeTrackHub, "on"); /* intro text */ puts("<P>"); -puts("Add your own private data hub for the browser."); +puts("Add your own unlisted data hub for the browser."); addIntro(); puts("<P>"); /* row for error message */ if (err) printf("<P><B> <span style='color:red; font-style:italic;'>Error</span> %s</B><P>", err); printf("Enter URL:"); hTextVar(hgHubDataText, "", 60); cgiMakeSubmitButton(); puts("</FORM>"); } -void helpPrivateHub() +void helpUnlistedHub() { -printf("Private hubs are constructed the same way as public hubs, but they " +printf("Unlisted hubs are constructed the same way as public hubs, but they " "aren't listed in hgcentral<BR>\n"); } -void doAddPrivateHub(struct cart *theCart, char *err) +void doAddUnlistedHub(struct cart *theCart, char *err) /* Write header and body of html page. */ { -cartWebStart(cart, database, "Add Private Hub"); -addPrivateHubForm(NULL, err); -helpPrivateHub(); +cartWebStart(cart, database, "Add Unlisted Hub"); +addUnlistedHubForm(NULL, err); +helpUnlistedHub(); cartWebEnd(cart); } -void hubSaveInCart(struct cart *cart, struct hubConnectStatus *hub) +static void enterHubInStatus(struct trackHub *tHub, boolean unlisted) +/* put the hub status in the hubStatus table */ { -char hubName[1024]; -char *oldHubTrashName = cartOptionalString(cart, hubFileVar()); -static struct tempName tn; -trashDirFile(&tn, "hub", "hub_", ".txt"); -char *hubTrashName = tn.forCgi; -FILE *f = mustOpen(hubTrashName, "w"); +struct sqlConnection *conn = hConnectCentral(); + +/* calculate dbList */ +struct dyString *dy = newDyString(1024); +struct hashEl *hel; +struct hashCookie cookie = hashFirst(tHub->genomeHash); +int dbCount = 0; -if (oldHubTrashName == NULL) +while ((hel = hashNext(&cookie)) != NULL) { - hub->id = -1; + dbCount++; + dyStringPrintf(dy,"%s,", hel->name); } -else + + +char query[512]; +safef(query, sizeof(query), "insert into %s (hubUrl,status,shortLabel, longLabel, dbList, dbCount) values (\"%s\",%d,\"%s\",\"%s\", \"%s\", %d)", + hubStatusTableName, tHub->url, unlisted ? 1 : 0, + tHub->shortLabel, tHub->longLabel, + dy->string, dbCount); +sqlUpdate(conn, query); +hDisconnectCentral(&conn); +} + +static unsigned getHubId(char *url, char **errorMessage) +/* find id for url in hubStatus table */ { - struct lineFile *lf = lineFileOpen(oldHubTrashName, TRUE); - int lineSize; - char *line; - int count = 1; +struct sqlConnection *conn = hConnectCentral(); +char query[512]; +char **row; +boolean foundOne = FALSE; +int id = 0; + +safef(query, sizeof(query), "select id,errorMessage from %s where hubUrl = \"%s\"", hubStatusTableName, url); - while (lineFileNext(lf, &line, &lineSize)) +struct sqlResult *sr = sqlGetResult(conn, query); + +while ((row = sqlNextRow(sr)) != NULL) { - count++; - fprintf(f, "%s\n", line); - } - lineFileClose(&lf); - unlink(oldHubTrashName); - hub->id = -count; + if (foundOne) + errAbort("more than one line in %s with hubUrl %s\n", + hubStatusTableName, url); + + foundOne = TRUE; + + char *thisId = row[0], *thisError = row[1]; + + if (!isEmpty(thisError)) + *errorMessage = cloneString(thisError); + + id = sqlUnsigned(thisId); } -hubWriteToFile(f, hub); -carefulClose(&f); +sqlFreeResult(&sr); -safef(hubName, sizeof(hubName), "%s%d", hgHubConnectHubVarPrefix, hub->id); -cartSetString(cart, hubName, "1"); +hDisconnectCentral(&conn); -cartSetString(cart, hubFileVar(), hubTrashName); +return id; } -void checkForNewHub(struct cart *cart) +static boolean hubHasDatabase(unsigned id, char *database) +/* check to see if hub specified by id supports database */ { -char *url = cartOptionalString(cart, hgHubDataText); +struct sqlConnection *conn = hConnectCentral(); +char query[512]; -if (url != NULL) +safef(query, sizeof(query), "select dbList from %s where id=%d", + hubStatusTableName, id); +char *dbList = sqlQuickString(conn, query); +boolean gotIt = FALSE; + +if (nameInCommaList(database, dbList)) + gotIt = TRUE; + +hDisconnectCentral(&conn); + +freeMem(dbList); + +return gotIt; +} + +static boolean fetchHub(char *url, boolean unlisted) { - struct hubConnectStatus *hub = NULL; +struct errCatch *errCatch = errCatchNew(); struct trackHub *tHub = NULL; +boolean gotWarning = FALSE; +unsigned id = 0; - struct errCatch *errCatch = errCatchNew(); if (errCatchStart(errCatch)) - tHub = trackHubOpen(url, "1"); + tHub = trackHubOpen(url, "1"); // open hub.. it'll get renamed later errCatchEnd(errCatch); if (errCatch->gotError) { + gotWarning = TRUE; warn(errCatch->message->string); - return; } errCatchFree(&errCatch); - AllocVar(hub); - hub->hubUrl = cloneString(url); - hub->errorMessage = ""; - hub->shortLabel = tHub->shortLabel; - hub->longLabel = tHub->longLabel; - hub->dbCount = 0; - AllocArray(hub->dbArray, 1); - hub->dbArray[0] = database; +if (gotWarning) + { + return 0; + } - hubSaveInCart(cart, hub); +if (hashLookup(tHub->genomeHash, database) != NULL) + { + enterHubInStatus(tHub, unlisted); } +else + { + warn("requested hub at %s does not have data for %s\n", url, database); + return 0; + } + +trackHubClose(&tHub); + +char *errorMessage = NULL; +id = getHubId(url, &errorMessage); +return id; +} + +static void getAndSetHubStatus(char *url, boolean set, boolean unlisted) +{ +char *errorMessage = NULL; +unsigned id; + +if ((id = getHubId(url, &errorMessage)) == 0) + { + if ((id = fetchHub(url, unlisted)) == 0) + return; + } +else if (!hubHasDatabase(id, database)) + { + warn("requested hub at %s does not have data for %s\n", url, database); + return; + } + +char hubName[32]; +safef(hubName, sizeof(hubName), "%s%u", hgHubConnectHubVarPrefix, id); +if (set) + cartSetString(cart, hubName, "1"); +} + +static unsigned findOrAddUrlInStatusTable( char *url, char **errorMessage) +/* find this url in the status table, and return its id and errorMessage (if an errorMessage exists) */ +{ +int id = 0; + +*errorMessage = NULL; + +if ((id = getHubId(url, errorMessage)) > 0) + return id; + +getAndSetHubStatus(url, FALSE, FALSE); + +if ((id = getHubId(url, errorMessage)) == 0) + errAbort("inserted new hubUrl %s, but cannot find it", url); + +return id; +} + +void hgHubConnectPublic() +/* Put up the list of external hubs and other controls for the page. */ +{ +printf("<B>Public Hubs</B><BR>"); +struct sqlConnection *conn = hConnectCentral(); +char query[512]; +safef(query, sizeof(query), "select hubUrl, shortLabel,longLabel,dbList from %s", + hubPublicTableName); +struct sqlResult *sr = sqlGetResult(conn, query); +char **row; + +boolean gotAnyRows = FALSE; +while ((row = sqlNextRow(sr)) != NULL) + { + char *url = row[0], *shortLabel = row[1], *longLabel = row[2], + *dbList = row[3]; + if (nameInCommaList(database, dbList)) + { + if (gotAnyRows) + webPrintLinkTableNewRow(); + else + { + webPrintLinkTableStart(); + gotAnyRows = TRUE; + } + char *errorMessage = NULL; + unsigned id = findOrAddUrlInStatusTable( url, &errorMessage); + + if ((id != 0) && isEmpty(errorMessage)) + { + webPrintLinkCellStart(); + char hubName[32]; + safef(hubName, sizeof(hubName), "%s%u", hgHubConnectHubVarPrefix, id); + cartMakeCheckBox(cart, hubName, FALSE); + webPrintLinkCellEnd(); + } + else if (!isEmpty(errorMessage)) + webPrintLinkCell("error"); + else + errAbort("cannot get id for hub with url %s\n", url); + + webPrintLinkCell(shortLabel); + if (isEmpty(errorMessage)) + webPrintLinkCell(longLabel); + else + { + char errorBuf[4*1024]; + safef(errorBuf, sizeof errorBuf, "Error: %s", errorMessage); + webPrintLinkCell(errorBuf); + } + webPrintLinkCell(url); + } + } +sqlFreeResult(&sr); + +if (gotAnyRows) + webPrintLinkTableEnd(); +else + printf("No Public Track Hubs for this genome assembly<BR>"); +hDisconnectCentral(&conn); +} + +void checkForNewHub(struct cart *cart) +/* see if the user just typed in a new hub url */ +{ +char *url = cartOptionalString(cart, hgHubDataText); + +if (url != NULL) + { + getAndSetHubStatus(url, TRUE, TRUE); + } +} + +static void clearHubStatus(char *url) +{ +struct sqlConnection *conn = hConnectCentral(); +char query[512]; + +safef(query, sizeof(query), "select id from %s where hubUrl = \"%s\"", hubStatusTableName, url); +unsigned id = sqlQuickNum(conn, query); + +if (id == 0) + errAbort("could not find url %s in status table (%s)\n", + url, hubStatusTableName); + +safef(query, sizeof(query), "delete from %s where hubUrl = \"%s\"", hubStatusTableName, url); + +sqlUpdate(conn, query); +hDisconnectCentral(&conn); + +printf("%s status has been cleared\n", url); +} + +static void doClearHub(struct cart *theCart) +{ +char *url = cartOptionalString(cart, hgHubDataText); + +if (url != NULL) + clearHubStatus(url); +else + errAbort("must specify url in %s\n", hgHubDataText); } void doMiddle(struct cart *theCart) /* Write header and body of html page. */ { cart = theCart; setUdcCacheDir(); if (cartVarExists(cart, hgHubDoAdd)) - doAddPrivateHub(cart, NULL); + doAddUnlistedHub(cart, NULL); +else if (cartVarExists(cart, hgHubDoClear)) + doClearHub(cart); else { cartWebStart(cart, NULL, pageTitle); - checkForNewHub(cart); - - printf("<FORM ACTION=\"%s\" METHOD=\"POST\" NAME=\"mainForm\">\n", destUrl); - cartSaveSession(cart); - cgiMakeHiddenVar(hgHubConnectRemakeTrackHub, "on"); printf( "<P>Track data hubs are collections of tracks from outside of UCSC that can be imported into " "the Genome Browser. To import a public hub check the box in the list below. " "After import the hub will show up as a group of tracks with its own blue " "bar and label underneath the main browser graphic, and in the configure page. </P>\n" ); makeGenomePrint(); + checkForNewHub(cart); printf("<BR><P>"); + printf("<FORM ACTION=\"%s\" METHOD=\"POST\" NAME=\"mainForm\">\n", destUrl); + cartSaveSession(cart); hgHubConnectPublic(); - printf("Contact <A HREF=\"mailto:genome@soe.ucsc.edu\"> genome@soe.ucsc.edu </A>to add a public hub.</P>\n"); + printf("<BR>Contact <A HREF=\"mailto:genome@soe.ucsc.edu\"> genome@soe.ucsc.edu </A>to add a public hub.</P>\n"); puts("<BR>"); - hgHubConnectPrivate(); + hgHubConnectUnlisted(); puts("<BR>"); + cgiMakeHiddenVar(hgHubConnectRemakeTrackHub, "on"); cgiMakeButton("Submit", "Use Selected Hubs"); puts("</FORM>"); makeNewHubButton(); - } cartWebEnd(); } -char *excludeVars[] = {"Submit", "submit", "hc_one_url", hgHubConnectCgiDestUrl, hgHubDoAdd, hgHubDataText, NULL}; +char *excludeVars[] = {"Submit", "submit", "hc_one_url", hgHubConnectCgiDestUrl, hgHubDoAdd, hgHubDoClear hgHubDataText, NULL}; int main(int argc, char *argv[]) /* Process command line. */ { oldVars = hashNew(10); cgiSpoof(&argc, argv); cartEmptyShell(doMiddle, hUserCookie(), excludeVars, oldVars); return 0; }