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.<br>"); + 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 <B>%s</B> as %s.<BR>\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 <B>%s</B>.\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 <B>%s</B> as %s.<BR>\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)