ae843e42c15f576fcbf9cc4a3671e615cf905a96
jcasper
Wed Jul 6 12:45:04 2016 -0700
Additional configuration options for session thumbnail creation and examples for same, refs #17469
diff --git src/hg/hgSession/hgSession.c src/hg/hgSession/hgSession.c
index 678e0e0..dad6f5d 100644
--- src/hg/hgSession/hgSession.c
+++ src/hg/hgSession/hgSession.c
@@ -817,62 +817,89 @@
htmlEncode(sessionName), (shareSession ? "may" : "may not"),
getSessionLink(encUserName, encSessionName),
getSessionEmailLink(encUserName, encSessionName));
cartCheckForCustomTracks(cart, 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 thumbnailAdd(char *encUserName, char *encSessionName, struct sqlConnection *conn)
-/* Create a thumbnail image for the gallery. Leaks memory from a generated filename string,
- * plus a couple of dyStrings. Returns without determining if the image creation
- * succeeded. */
+int thumbnailAdd(char *encUserName, char *encSessionName, struct sqlConnection *conn, struct dyString *dyMessage)
+/* Create a thumbnail image for the gallery. If the necessary tools can't be found,
+ * add a warning message to dyMessage unless the hg.conf setting
+ * sessionThumbnail.suppressWarning is set to "on".
+ * Leaks memory from a generated filename string, plus a couple of dyStrings.
+ * Returns without determining if image creation succeeded (it happens in a separate
+ * thread); the return value is 0 if a message was added to dyMessage, otherwise it's 1. */
{
char query[4096];
char **row;
struct sqlResult *sr;
+
+char *suppressConvert = cfgOption("sessionThumbnail.suppress");
+if (suppressConvert != NULL && sameString(suppressConvert, "on"))
+ return 1;
+
+char *convertPath = cfgOption("sessionThumbnail.convertPath");
+if (convertPath == NULL)
+ convertPath = cloneString("convert");
+char convertTestCmd[4096];
+safef(convertTestCmd, sizeof(convertTestCmd), "which %s >& /dev/null", convertPath);
+int convertTestResult = system(convertTestCmd);
+if (convertTestResult != 0)
+ {
+ dyStringPrintf(dyMessage,
+ "Note: A thumbnail image for this session was not created because the ImageMagick convert "
+ "tool could not be found. Please contact your mirror administrator to resolve this "
+ "issue, either by installing convert so that it is part of the webserver's PATH, "
+ "by adding the \"sessionThumbnail.convertPath\" option to the mirror's hg.conf file "
+ "to specify the path to that program, or by adding \"sessionThumbnail.suppress=on\" to "
+ "the mirror's hg.conf file to suppress this warning.
");
+ return 0;
+ }
+
sqlSafef(query, sizeof(query),
"select m.idx, n.firstUse from gbMembers m join namedSessionDb n on m.userName = n.userName "
"where m.userName = \"%s\" and n.sessionName = \"%s\"",
encUserName, encSessionName);
sr = sqlGetResult(conn, query);
row = sqlNextRow(sr);
if (row == NULL)
errAbort("cannot add session to gallery; user %s, session %s",
encUserName, encSessionName);
char *destFile = sessionThumbnailFilePath(row[0], encSessionName, row[1]);
if (destFile != NULL)
{
struct dyString *hgTracksUrl = dyStringNew(0);
addSessionLink(hgTracksUrl, encUserName, encSessionName, FALSE);
struct dyString *renderUrl =
dyStringSub(hgTracksUrl->string, "cgi-bin/hgTracks", "cgi-bin/hgRenderTracks");
dyStringAppend(renderUrl, "&pix=640");
char *renderCmd[] = {"wget", "-q", "-O", "-", renderUrl->string, NULL};
- char *convertCmd[] = {"convert", "-", "-resize", "320", "-crop", "320x240+0+0", destFile, NULL};
+ char *convertCmd[] = {convertPath, "-", "-resize", "320", "-crop", "320x240+0+0", destFile, NULL};
char **cmdsImg[] = {renderCmd, convertCmd, NULL};
pipelineOpen(cmdsImg, pipelineWrite, "/dev/null", NULL);
}
sqlFreeResult(&sr);
+return 1;
}
void thumbnailRemove(char *encUserName, char *encSessionName, struct sqlConnection *conn)
/* Unlink thumbnail image for the gallery. Leaks memory from a generated filename string. */
{
char query[4096];
char **row;
struct sqlResult *sr;
sqlSafef(query, sizeof(query),
"select m.idx, n.firstUse from gbMembers m join namedSessionDb n on m.userName = n.userName "
"where m.userName = \"%s\" and n.sessionName = \"%s\"",
encUserName, encSessionName);
sr = sqlGetResult(conn, query);
row = sqlNextRow(sr);
@@ -1037,31 +1064,31 @@
if (newGallery != inGallery)
{
sqlSafef(query, sizeof(query), "UPDATE %s SET shared = %d "
"WHERE userName = '%s' AND sessionName = '%s';",
namedSessionTable, newGallery == TRUE ? 2 : 1, encUserName, encSessionName);
sqlUpdate(conn, query);
sessionTouchLastUse(conn, encUserName, encSessionName);
dyStringPrintf(dyMessage,
"Marked session %s as %s.
\n",
htmlEncode(sessionName),
(newGallery == TRUE ? "added to gallery" : "removed from public listing"));
if (newGallery == FALSE)
thumbnailRemove(encUserName, encSessionName, conn);
if (newGallery == TRUE)
- thumbnailAdd(encUserName, encSessionName, conn);
+ thumbnailAdd(encUserName, encSessionName, conn, dyMessage);
didSomething = TRUE;
}
}
hashFree(&galleryHash);
}
cartHelList = cartFindPrefix(cart, hgsSharePrefix);
if (cartHelList != NULL)
{
struct hash *sharedHash = hashNew(0);
char **row;
struct sqlResult *sr;
sqlSafef(query, sizeof(query),
"select sessionName,shared from %s where userName = '%s'",
namedSessionTable, encUserName);
@@ -1341,58 +1368,58 @@
char *encNewName = cgiEncodeFull(newName);
sqlSafef(query, sizeof(query),
"UPDATE %s set sessionName = '%s' WHERE userName = '%s' AND sessionName = '%s';",
namedSessionTable, encNewName, encUserName, encSessionName);
sqlUpdate(conn, query);
dyStringPrintf(dyMessage, "Changed session name from %s to %s.\n",
sessionName, newName);
sessionName = newName;
encSessionName = encNewName;
renamePrefixedCartVar(hgsEditPrefix, encOldSessionName, encNewName);
renamePrefixedCartVar(hgsLoadPrefix, encOldSessionName, encNewName);
renamePrefixedCartVar(hgsDeletePrefix, encOldSessionName, encNewName);
if (shared >= 2)
{
thumbnailRemove(encUserName, encSessionName, conn);
- thumbnailAdd(encUserName, encNewName, 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))
newShared = cartBoolean(cart, sharedVarName) ? 1 : 0;
if (cgiBooleanDefined(galleryVarName))
newShared = cartBoolean(cart, galleryVarName) ? 2 : newShared;
if (newShared != shared)
{
sqlSafef(query, sizeof(query),
"UPDATE %s set shared = %d WHERE userName = '%s' AND sessionName = '%s';",
namedSessionTable, newShared, encUserName, encSessionName);
sqlUpdate(conn, query);
dyStringPrintf(dyMessage, "Marked session %s as %s.
\n",
htmlEncode(sessionName), (newShared>0 ? newShared>=2 ? "shared in public listing" :
"shared, but not in public listing" : "unshared"));
if (shared >= 2 && newShared < 2)
thumbnailRemove(encUserName, encSessionName, conn);
if (shared < 2 && newShared >= 2)
- thumbnailAdd(encUserName, encSessionName, conn);
+ thumbnailAdd(encUserName, encSessionName, conn, dyMessage);
}
cartRemove(cart, sharedVarName);
cartRemove(cart, galleryVarName);
char shadowVarName[512];
safef(shadowVarName, sizeof(shadowVarName), "%s%s", cgiBooleanShadowPrefix(), sharedVarName);
cartRemove(cart, shadowVarName);
safef(shadowVarName, sizeof(shadowVarName), "%s%s", cgiBooleanShadowPrefix(), galleryVarName);
cartRemove(cart, shadowVarName);
}
if (gotSettings)
{
struct hash *settingsHash = raFromString(settings);
char *description = hashFindVal(settingsHash, "description");
char *newDescription = cartOptionalString(cart, hgsNewSessionDescription);
if (newDescription != NULL)