c12c003485da26742d76b787bb1c7d148a4d58f5
rhead
Thu Apr 28 19:04:04 2011 -0700
Updated several places to reflect the actual expiration times of custom tracks and BLAT results that are saved in sessions (redmine #3462).
diff --git src/hg/hgSession/hgSession.c src/hg/hgSession/hgSession.c
index 7dc9562..5881a49 100644
--- src/hg/hgSession/hgSession.c
+++ src/hg/hgSession/hgSession.c
@@ -1,1253 +1,1251 @@
/* hgSession - Interface with wiki login and do session saving/loading. */
#include "common.h"
#include "hash.h"
#include "htmshell.h"
#include "cheapcgi.h"
#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 "hgSession.h"
static char const rcsid[] = "$Id: hgSession.c,v 1.53 2010/03/05 22:26:29 angie Exp $";
void usage()
/* Explain usage and exit. */
{
errAbort(
"hgSession - Interface with wiki login and do session saving/loading.\n"
"usage:\n"
" hgSession The sign-in page is handled by our "
"wiki system:\n", wikiHost);
printf("click here to sign in.\n",
wikiLinkUserLoginUrl(cartSessionId(cart)));
printf("The wiki also serves as a forum for users "
"to share knowledge and ideas.\n");
}
void showCartLinks()
/* Print out links to cartDump and cartReset. */
{
char *session = cartSidUrlString(cart);
char returnAddress[512];
safef(returnAddress, sizeof(returnAddress), "%s?%s", hgSessionName(), session);
printf("Click here to "
"reset the browser user interface settings to their defaults.\n",
session, cgiEncodeFull(returnAddress));
}
char *destAppScriptName()
/* Return the complete path (/cgi-bin/... on our systems) of the destination
* CGI for share-able links. Currently hardcoded; there might be a way to
* offer the user a choice. */
{
static char *thePath = NULL;
if (thePath == NULL)
{
char path[512];
char buf[512];
char *ptr = NULL;
safef(path, sizeof(path), "%s", cgiScriptName());
ptr = strrchr(path, '/');
if (ptr == NULL)
path[0] = '\0';
else
*(ptr+1) = '\0';
safef(buf, sizeof(buf), "%s%s", path, "hgTracks");
thePath = cloneString(buf);
}
return thePath;
}
void addSessionLink(struct dyString *dy, char *userName, char *sessionName,
boolean encode)
/* Add to dy an URL that tells hgSession to load a saved session.
* If encode, cgiEncodeFull the URL. */
{
struct dyString *dyTmp = dyStringNew(1024);
dyStringPrintf(dyTmp, "http://%s%s?hgS_doOtherUser=submit&"
"hgS_otherUserName=%s&hgS_otherUserSessionName=%s",
cgiServerName(), destAppScriptName(), userName, sessionName);
if (encode)
{
dyStringPrintf(dy, "%s", cgiEncodeFull(dyTmp->string));
}
else
{
dyStringPrintf(dy, "%s", dyTmp->string);
}
dyStringFree(&dyTmp);
}
char *getSessionLink(char *encUserName, char *encSessionName)
/* Form a link that will take the user to a bookmarkable page that
* will load the given session. */
{
struct dyString *dy = dyStringNew(1024);
dyStringPrintf(dy, "Browser\n");
return dyStringCannibalize(&dy);
}
char *getSessionEmailLink(char *encUserName, char *encSessionName)
/* Invoke mailto: with a cgi-encoded link that will take the user to a
* bookmarkable page that will load the given session. */
{
struct dyString *dy = dyStringNew(1024);
dyStringPrintf(dy, "Email\n");
return dyStringCannibalize(&dy);
}
void addUrlLink(struct dyString *dy, char *url, boolean encode)
/* Add to dy an URL that tells hgSession to load settings from the given url.
* If encode, cgiEncodeFull the whole thing. */
{
struct dyString *dyTmp = dyStringNew(1024);
char *encodedUrl = cgiEncodeFull(url);
dyStringPrintf(dyTmp, "http://%s%s?hgS_doLoadUrl=submit&hgS_loadUrlName=%s",
cgiServerName(), destAppScriptName(), encodedUrl);
if (encode)
{
dyStringPrintf(dy, "%s", cgiEncodeFull(dyTmp->string));
}
else
{
dyStringPrintf(dy, "%s", dyTmp->string);
}
freeMem(encodedUrl);
dyStringFree(&dyTmp);
}
char *getUrlLink(char *url)
/* Form a link that will take the user to a bookmarkable page that
* will load the given url. */
{
struct dyString *dy = dyStringNew(1024);
dyStringPrintf(dy, "Browser\n");
return dyStringCannibalize(&dy);
}
char *getUrlEmailLink(char *url)
/* Invoke mailto: with a cgi-encoded link that will take the user to a
* bookmarkable page that will load the given url. */
{
struct dyString *dy = dyStringNew(1024);
dyStringPrintf(dy, "Email\n");
return dyStringCannibalize(&dy);
}
static char *getSetting(char *settings, char *name)
/* Dig out one setting from a settings string that we're only going to
* look at once (so we don't keep the hash around). */
{
if (isEmpty(settings))
return NULL;
struct hash *settingsHash = raFromString(settings);
char *val = cloneString(hashFindVal(settingsHash, name));
hashFree(&settingsHash);
return val;
}
void showExistingSessions(char *userName)
/* Print out a table with buttons for sharing/unsharing/loading/deleting
* previously saved sessions. */
{
struct sqlConnection *conn = hConnectCentral();
struct sqlResult *sr = NULL;
char **row = NULL;
char query[512];
boolean foundAny = FALSE;
char *encUserName = cgiEncodeFull(userName);
boolean gotSettings = (sqlFieldIndex(conn, namedSessionTable, "settings") >= 0);
printf(" Note: the session has at least one active custom "
"track (in database ");
for (sln = liveDbList; sln != NULL; sln = sln->next)
dyStringPrintf(dyMessage, "%s%s",
cartSidUrlString(cart), sln->name,
sln->name, (sln->next ? sln->next->next ? ", " : " and " : ""));
dyStringAppend(dyMessage, "; click on the database link "
"to manage custom tracks). ");
}
if (gotExpiredCT)
{
slSort(&expiredDbList, slNameCmp);
dyStringPrintf(dyMessage,
" Note: the session has at least one expired custom "
"track (in database ");
for (sln = expiredDbList; sln != NULL; sln = sln->next)
dyStringPrintf(dyMessage, "%s%s",
sln->name, (sln->next ? sln->next->next ? ", " : " and " : ""));
dyStringPrintf(dyMessage,
"), so it may not appear as originally intended. ");
}
dyStringPrintf(dyMessage,
"Custom tracks are subject to an expiration policy described in the "
- "custom "
- "track documentation. In order to keep a custom track from expiring, "
- "you can periodically view the custom track in the genome browser.My Sessions
\n");
printf("\n");
safef(query, sizeof(query), "SELECT sessionName, shared, firstUse from %s "
"WHERE userName = '%s' ORDER BY sessionName;",
namedSessionTable, encUserName);
sr = sqlGetResult(conn, query);
printf("
\n");
printf("\n");
sqlFreeResult(&sr);
hDisconnectCentral(&conn);
}
void showOtherUserOptions()
/* Print out inputs for loading another user's saved session. */
{
printf("session name created on use this "
"
session delete this
session share with
others? link to "
"
sessionsend to ");
while ((row = sqlNextRow(sr)) != NULL)
{
char *encSessionName = row[0];
char *sessionName = cgiDecodeClone(encSessionName);
char *link = NULL;
boolean shared = atoi(row[1]);
char *firstUse = row[2];
char buf[512];
printf("
mail ", link);
freez(&link);
foundAny = TRUE;
struct slName *sn = slNameNew(sessionName);
slAddHead(&existingSessionNames, sn);
}
if (!foundAny)
printf(" ");
if (gotSettings)
printf("",
hgSessionName(), cartSidUrlString(cart), hgsDoSessionDetail, encSessionName);
htmlTextOut(sessionName);
char *spacePt = strchr(firstUse, ' ');
if (spacePt != NULL) *spacePt = '\0';
if (gotSettings)
printf("");
printf(" "
"%s ", firstUse);
safef(buf, sizeof(buf), "%s%s", hgsLoadPrefix, encSessionName);
cgiMakeButton(buf, "use");
printf(" ");
safef(buf, sizeof(buf), "%s%s", hgsDeletePrefix, encSessionName);
char command[512];
safef(command, sizeof(command), confirmDeleteFormat, sessionName);
cgiMakeOnClickSubmitButton(command, buf, "delete");
printf(" ");
safef(buf, sizeof(buf), "%s%s", hgsSharePrefix, encSessionName);
cgiMakeCheckBoxJS(buf, shared, "onchange=\"document.mainForm.submit();\"");
link = getSessionLink(encUserName, encSessionName);
printf(" %s \n", link);
freez(&link);
link = getSessionEmailLink(encUserName, encSessionName);
printf("%s \n");
printf(" (none) "
" \n");
printf("\n");
printf("
\n");
}
void showLoadingOptions(char *userName, boolean savedSessionsSupported)
/* Show options for loading settings from another user's session, a file
* or URL. */
{
printf(" \n"
""
"Use settings from another user's saved session: \n");
printf(" user: \n");
cgiMakeOnKeypressTextVar(hgsOtherUserName,
cartUsualString(cart, hgsOtherUserName, ""),
20, "return noSubmitOnEnter(event);");
printf(" session name: \n");
cgiMakeOnKeypressTextVar(hgsOtherUserSessionName,
cartUsualString(cart, hgsOtherUserSessionName, ""),
20, jsPressOnEnter(hgsDoOtherUser));
printf(" ");
cgiMakeButton(hgsDoOtherUser, "submit");
printf(" \n");
printf("Restore Settings
\n");
if (savedSessionsSupported)
showOtherUserOptions();
printf("\n");
printf("
\n");
printf("\n");
}
void showSavingOptions(char *userName)
/* Show options for saving a new named session in our db or to a file. */
{
static char *textOutCompressMenu[] = textOutCompressMenuContents;
static char *textOutCompressValues[] = textOutCompressValuesContents;
static int textOutCompressMenuSize = ArraySize(textOutCompressMenu) - 1;
printf(" \n");
printf("Use settings from a local file: \n");
printf("\n",
hgsLoadLocalFileName);
printf(" ");
cgiMakeButton(hgsDoLoadLocal, "submit");
printf(" \n");
printf(" \n");
printf("Use settings from a URL (http://..., ftp://...):"
" \n");
printf("\n");
cgiMakeOnKeypressTextVar(hgsLoadUrlName,
cartUsualString(cart, hgsLoadUrlName, ""),
20, jsPressOnEnter(hgsDoLoadUrl));
printf(" ");
cgiMakeButton(hgsDoLoadUrl, "submit");
printf(" Save Settings
\n");
printf("\n");
if (isNotEmpty(userName))
{
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
{
cartWebStart(cart, NULL, "Session Management");
jsInit();
}
printf("See the Sessions User's Guide "
"for more information about this tool.\n");
showCartLinks();
printf("\n");
}
void showLinkingTemplates(char *userName)
/* Explain how to create links to us for sharing sessions. */
{
struct dyString *dyUrl = dyStringNew(1024);
webNewSection("Sharing Sessions");
printf("There are several ways to share saved sessions with others.\n");
printf(" \n"
"Save current settings as named session:"
" \n");
printf(" name: \n");
cgiMakeOnKeypressTextVar(hgsNewSessionName,
cartUsualString(cart, "db", NULL),
20, jsPressOnEnter(hgsDoNewSession));
printf(" ");
cgiMakeCheckBox(hgsNewSessionShare,
cartUsualBoolean(cart, hgsNewSessionShare, TRUE));
printf("allow this session to be loaded by others\n");
printf(" ");
printf(" ");
if (existingSessionNames)
{
struct dyString *js = dyStringNew(1024);
struct slName *sn;
dyStringAppend(js, "var si = document.getElementsByName('" hgsNewSessionName "'); ");
dyStringAppend(js, "if (si[0] && ( ");
for (sn = existingSessionNames; sn != NULL; sn = sn->next)
{
dyStringPrintf(js, "si[0].value == ");
dyStringQuoteString(js, '\'', sn->name);
dyStringPrintf(js, "%s", (sn->next ? " || " : " )) { "));
}
dyStringAppend(js, "return confirm('This will overwrite the contents of the existing "
"session ' + si[0].value + '. Proceed?'); ");
dyStringAppend(js, "}");
cgiMakeOnClickSubmitButton(js->string, hgsDoNewSession, "submit");
dyStringFree(&js);
}
else
cgiMakeButton(hgsDoNewSession, "submit");
printf(" \n");
}
printf(" \n");
printf("Save current settings to a local file: \n");
printf(" file: \n");
cgiMakeOnKeypressTextVar(hgsSaveLocalFileName,
cartUsualString(cart, hgsSaveLocalFileName, ""),
20, jsPressOnEnter(hgsDoSaveLocal));
printf(" ");
printf("file type returned: ");
cgiMakeDropListFull(hgsSaveLocalFileCompress,
textOutCompressMenu, textOutCompressValues, textOutCompressMenuSize,
cartUsualString(cart, hgsSaveLocalFileCompress, textOutCompressNone),
NULL);
printf(" ");
printf(" ");
cgiMakeButton(hgsDoSaveLocal, "submit");
printf(" \n");
printf("(leave file blank to get output in "
"browser window) \n");
printf("\n");
if (userName != NULL)
{
printf("
\n");
dyStringFree(&dyUrl);
}
void doMainPage(char *message)
/* Login status/links and session controls. */
{
puts("Content-Type:text/html\n");
if (wikiLinkEnabled())
{
char *wikiUserName = wikiLinkUserName();
if (wikiUserName)
welcomeUser(wikiUserName);
else
offerLogin();
if (isNotEmpty(message))
{
if (cartVarExists(cart, hgsDoSessionDetail))
webNewSection("Session Details");
else
webNewSection("Updated Session");
puts(message);
}
showSessionControls(wikiUserName, TRUE, TRUE);
showLinkingTemplates(wikiUserName);
}
else
{
if (isNotEmpty(message))
{
if (cartVarExists(cart, hgsDoSessionDetail))
webNewSection("Session Details");
else
cartWebStart(cart, NULL, "Updated Session");
jsInit();
puts(message);
showSessionControls(NULL, FALSE, TRUE);
}
else
showSessionControls(NULL, FALSE, FALSE);
showLinkingTemplates(NULL);
}
cartWebEnd();
}
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);
cartRemovePrefix(cart, hgsLoadPrefix);
cartRemovePrefix(cart, hgsLoadLocalFileName);
cartRemovePrefix(cart, hgsDeletePrefix);
cartRemovePrefix(cart, hgsDo);
cartRemove(cart, hgsOldSessionName);
cartRemove(cart, hgsCancel);
}
void checkForCustomTracks(struct dyString *dyMessage);
#define INITIAL_USE_COUNT 0
char *doNewSession()
/* Save current settings in a new named session.
* Return a message confirming what we did. */
{
struct dyString *dyMessage = dyStringNew(2048);
char *sessionName = trimSpaces(cartString(cart, hgsNewSessionName));
char *encSessionName = cgiEncodeFull(sessionName);
boolean shareSession = cartBoolean(cart, hgsNewSessionShare);
char *userName = wikiLinkUserName();
char *encUserName = cgiEncodeFull(userName);
struct sqlConnection *conn = hConnectCentral();
if (sqlTableExists(conn, namedSessionTable))
{
struct sqlResult *sr = NULL;
struct dyString *dy = dyStringNew(16 * 1024);
char **row;
char *firstUse = "now()";
int useCount = INITIAL_USE_COUNT;
char firstUseBuf[32];
/* If this session already existed, preserve its firstUse and useCount. */
dyStringPrintf(dy, "SELECT firstUse, useCount FROM %s "
"WHERE userName = '%s' AND sessionName = '%s';",
namedSessionTable, encUserName, encSessionName);
sr = sqlGetResult(conn, dy->string);
if ((row = sqlNextRow(sr)) != NULL)
{
safef(firstUseBuf, sizeof(firstUseBuf), "'%s'", row[0]);
firstUse = firstUseBuf;
useCount = atoi(row[1]) + 1;
}
sqlFreeResult(&sr);
/* Remove pre-existing session (if any) before updating. */
dyStringClear(dy);
dyStringPrintf(dy, "DELETE FROM %s WHERE userName = '%s' AND "
"sessionName = '%s';",
namedSessionTable, encUserName, encSessionName);
sqlUpdate(conn, dy->string);
dyStringClear(dy);
dyStringPrintf(dy, "INSERT INTO %s ", namedSessionTable);
dyStringAppend(dy, "(userName, sessionName, contents, shared, "
"firstUse, lastUse, useCount) VALUES (");
dyStringPrintf(dy, "'%s', '%s', ", encUserName, encSessionName);
dyStringAppend(dy, "'");
cleanHgSessionFromCart(cart);
cartEncodeState(cart, dy);
dyStringAppend(dy, "', ");
dyStringPrintf(dy, "%d, ", (shareSession ? 1 : 0));
dyStringPrintf(dy, "%s, now(), %d);", firstUse, useCount);
sqlUpdate(conn, dy->string);
dyStringFree(&dy);
if (useCount > INITIAL_USE_COUNT)
dyStringPrintf(dyMessage,
"Overwrote the contents of session %s "
"(that %s be shared with other users). "
"%s %s",
htmlEncode(sessionName), (shareSession ? "may" : "may not"),
getSessionLink(encUserName, encSessionName),
getSessionEmailLink(encUserName, encSessionName));
else
dyStringPrintf(dyMessage,
"Added a new session %s that %s be shared with other users. "
"%s %s",
htmlEncode(sessionName), (shareSession ? "may" : "may not"),
getSessionLink(encUserName, encSessionName),
getSessionEmailLink(encUserName, encSessionName));
checkForCustomTracks(dyMessage);
}
else
dyStringPrintf(dyMessage,
"Sorry, required table %s does not exist yet in the central "
"database (%s). Please ask a developer to create it using "
"kent/src/hg/lib/namedSessionDb.sql .",
namedSessionTable, sqlGetDatabase(conn));
hDisconnectCentral(&conn);
return dyStringCannibalize(&dyMessage);
}
void checkForCustomTracks(struct dyString *dyMessage)
/* Scan cart for ctfile_
Note: the session contains saved BLAT results. "); else dyStringPrintf(dyMessage, "
Note: the session contains an expired reference to " "previously saved BLAT results, so it may not appear as " "originally intended. "); dyStringPrintf(dyMessage, - "BLAT results are subject to the same expiration policy as " - "custom " - "tracks. In order to keep BLAT results from expiring, you can " - "periodically view them in the genome browser.
"); + "BLAT results are subject to an " + "" + "expiration policy."); } } char *doUpdateSessions() /* Look for cart variables matching prefixes for sharing/unsharing, * loading or deleting a previously saved session. * Return a message confirming what we did, or NULL if no such variables * were in the cart. */ { struct dyString *dyMessage = dyStringNew(1024); struct hashEl *cartHelList = NULL, *hel = NULL; struct sqlConnection *conn = hConnectCentral(); char *userName = wikiLinkUserName(); char *encUserName = cgiEncodeFull(userName); boolean didSomething = FALSE; char query[512]; cartHelList = cartFindPrefix(cart, hgsSharePrefix); if (cartHelList != NULL) { struct hash *sharedHash = hashNew(0); char **row; struct sqlResult *sr; safef(query, sizeof(query), "select sessionName,shared from %s where userName = '%s'", namedSessionTable, encUserName); sr = sqlGetResult(conn, query); while ((row = sqlNextRow(sr)) != NULL) hashAddInt(sharedHash, row[0], atoi(row[1])); sqlFreeResult(&sr); for (hel = cartHelList; hel != NULL; hel = hel->next) { char *encSessionName = hel->name + strlen(hgsSharePrefix); char *sessionName = cgiDecodeClone(encSessionName); boolean alreadyShared = hashIntVal(sharedHash, encSessionName); boolean shared = cartUsualBoolean(cart, hel->name, TRUE); if (shared != alreadyShared) { safef(query, sizeof(query), "UPDATE %s SET shared = %d " "WHERE userName = '%s' AND sessionName = '%s';", namedSessionTable, shared, encUserName, encSessionName); sqlUpdate(conn, query); sessionTouchLastUse(conn, encUserName, encSessionName); dyStringPrintf(dyMessage, "Marked session %s as %s.\n" "
\n"); sqlFreeResult(&sr); } else errAbort("doSessionDetail: got no results from query: