/* Handle details pages for wiggle tracks. */ #include "common.h" #include "cart.h" #include "hgc.h" #include "hCommon.h" #include "hgColors.h" #include "hgConfig.h" #include "obscure.h" #include "binRange.h" #include "web.h" #include "net.h" #include "grp.h" #include "hui.h" #include "htmlPage.h" #include "wikiLink.h" #include "wikiTrack.h" #define ITEM_SCORE_DEFAULT "1000" #define ADD_ITEM_COMMENT_DEFAULT "add comments" static char *colorMenuJS = "onchange=\"updateColorSelectBox();\" style=\"width:8em;\""; static void colorMenuOutput() /* the item color pull-down menu in the create item form */ { hPrintf("\n"); hPrintf("\n"); } static char *encodedHgcReturnUrl(int id, char *table) /* Return a CGI-encoded hgc URL with hgsid and given id. Free when done. */ { char retBuf[1024]; int o = cartUsualInt(cart, "o", winStart); safef(retBuf, sizeof(retBuf), "http://%s/cgi-bin/hgc?%s&g=%s&c=%s&o=%d&l=%d&r=%d&db=%s&i=%d", cgiServerNamePort(), cartSidUrlString(cart), table, seqName, o, winStart, winEnd, database, id); return cgiEncode(retBuf); } static char *wikiTrackUserLoginUrl(int id, char *table) /* Return the URL for the wiki user login page. */ { char *retEnc = encodedHgcReturnUrl(id, table); char buf[2048]; if (! wikiLinkEnabled()) errAbort("wikiLinkUserLoginUrl called when wiki is not enabled (specified " "in hg.conf)."); safef(buf, sizeof(buf), "%s/index.php?title=Special:UserloginUCSC&returnto=%s", cfgOptionDefault(CFG_WIKI_URL, NULL), retEnc); freez(&retEnc); return(cloneString(buf)); } void offerLogin(int id, char *loginType, char *table) /* display login prompts to the wiki when user isn't already logged in */ { char *wikiHost = wikiLinkHost(); char *loginUrl = wikiTrackUserLoginUrl(id, table); printf("

Please login to %s the annotation track.

\n", loginType); printf("

The login page is handled by our " "wiki system:\n", wikiHost); printf("click here to login.
\n", loginUrl); printf("The wiki also serves as a forum for users " "to share knowledge and ideas.\n

\n"); freeMem(loginUrl); freeMem(wikiHost); webIncludeHelpFile("wikiTrackAddCommentHelp", TRUE); webIncludeHelpFile("wikiTrack", TRUE); } static void startForm(char *name, char *actionType) { hPrintf("
\n\n", name, name, hgcName()); cartSaveSession(cart); cgiMakeHiddenVar("g", actionType); cgiContinueHiddenVar("c"); cgiContinueHiddenVar("o"); hPrintf("\n"); cgiContinueHiddenVar("l"); cgiContinueHiddenVar("r"); hPrintf("\n"); } static struct bed *multipleItems(struct wikiTrack *item) { struct sqlResult *sr; char **row; struct sqlConnection *wikiConn = wikiConnect(); char query[1024]; struct bed *bedList = NULL; safef(query, ArraySize(query), "SELECT chrom,chromStart,chromEnd,id FROM %s " "WHERE descriptionKey='%s' ORDER BY chrom,chromStart;", WIKI_TRACK_TABLE, item->descriptionKey); sr = sqlGetResult(wikiConn, query); while ( (row = sqlNextRow(sr)) != NULL) { int elId = sqlUnsigned(row[3]); if (elId == item->id) continue; struct bed *bed; AllocVar(bed); bed->chrom = cloneString(row[0]); bed->chromStart = sqlUnsigned(row[1]); bed->chromEnd = sqlUnsigned(row[2]); bed->score = elId; slAddHead(&bedList,bed); } sqlFreeResult(&sr); slSort(&bedList, bedCmpExtendedChr); wikiDisconnect(&wikiConn); return bedList; } static void displayItem(struct wikiTrack *item, char *userName) /* given an already fetched item, get the item description from * the wiki. Put up edit form(s) if userName is not NULL */ { boolean geneAnnotation = FALSE; char *url = cfgOptionDefault(CFG_WIKI_URL, NULL); if (isNotEmpty(item->geneSymbol) && differentWord(item->geneSymbol,"0")) { hPrintf("This is a UCSC gene annotation
\n"); geneAnnotation = TRUE; } else hPrintf("This is a genome location annotation, not a gene annotation.\n"); printPosOnChrom(item->chrom, item->chromStart, item->chromEnd, item->strand, FALSE, item->name); if (geneAnnotation) { struct bed *itemList = multipleItems(item); if (slCount(itemList) > 0) { hPrintf("  This gene symbol '%s' is also found in the following " "locations:
\n", item->name); struct bed *el; for (el = itemList; el; el = el->next) { printf("    %s: " "", item->name, hgTracksPathAndSettings(), database, el->chrom, el->chromStart+1, el->chromEnd); printf("%s:%d-%d
\n", el->chrom, el->chromStart+1, el->chromEnd); } } } hPrintf("Created %s by: ", item->creationDate); hPrintf("%s
\n", url, item->owner, item->owner); hPrintf("Most recent quick update: %s
\n", item->lastModifiedDate); boolean editor = isWikiEditor(userName); if ((NULL != userName) && (editor || (sameWord(userName, item->owner) && !geneAnnotation))) { hPrintf("(comments for deleted items remain in the wiki, with a " "note
  that the item has been deleted.)

\n"); startForm("deleteForm", G_DELETE_WIKI_ITEM); char idString[128]; safef(idString, ArraySize(idString), "%d", item->id); cgiMakeHiddenVar("i", idString); hPrintf("\n"); webPrintLinkTableStart(); webPrintLinkCellStart(); if (editor && (differentWord(userName, item->owner) || geneAnnotation)) hPrintf("Editor '%s' has deletion rights  ", userName); else hPrintf("Owner '%s' has deletion rights  ", item->owner); webPrintLinkCellEnd(); webPrintLinkCellStart(); cgiMakeButton("submit", "DELETE"); webPrintLinkCellEnd(); webPrintLinkCellStart(); hPrintf(" (no questions asked)"); webPrintLinkCellEnd(); webPrintLinkTableEnd(); hPrintf("\n
\n"); } hPrintf("View the wiki article " "%s: to see " "existing comments.
\n", url, item->descriptionKey, item->descriptionKey); if (NULL != userName) hPrintf("Mark this wiki article as " "watched" " to receive email notices of any comment additions.
\n", url, item->descriptionKey); hPrintf("
\n"); if (NULL == userName) { if (! wikiTrackReadOnly() ) /* read-only option 2012-06-25 */ offerLogin(item->id, "add comments to items on", WIKI_TRACK_TABLE); } else if (emailVerified(TRUE)) /* do print message when not verified */ { startForm("addComments", G_ADD_WIKI_COMMENTS); char idString[128]; safef(idString, ArraySize(idString), "%d", item->id); cgiMakeHiddenVar("i", idString); hPrintf("\n"); webPrintLinkTableStart(); /* first row is a title line */ char label[256]; safef(label, ArraySize(label), "'%s' quick add comments to item '%s'\n", userName, item->name); webPrintWideLabelCell(label, 2); webPrintLinkTableNewRow(); /* second row is initial comment/description text entry */ webPrintWideCellStart(2, HG_COL_TABLE); cgiMakeTextArea(NEW_ITEM_COMMENT, ADD_ITEM_COMMENT_DEFAULT, 3, 70); webPrintLinkCellEnd(); webPrintLinkTableNewRow(); /*webPrintLinkCellStart(); more careful explicit alignment */ hPrintf("", HG_COL_TABLE); cgiMakeButton("submit", "add comments"); hPrintf("\n\n"); webPrintLinkCellEnd(); /*webPrintLinkCellStart(); doesn't valign center properly */ hPrintf("", HG_COL_TABLE); hPrintf("\n
", hgTracksName()); cgiMakeButton("cancel", "return to tracks display"); hPrintf("\n
\n"); webPrintLinkCellEnd(); webPrintLinkTableEnd(); hPrintf("For more extensive edits, please edit the "); hPrintf("wiki article %s " "in the wiki editing system.
", url, item->descriptionKey, item->descriptionKey); webIncludeHelpFile("wikiTrackAddCommentHelp", TRUE); webIncludeHelpFile("wikiTrack", TRUE); } } /* displayItem() */ void outputJavaScript() /* java script functions used in the create item form */ { hPrintf("\n"); } void doWikiTrack(char *wikiItemId, char *chrom, int winStart, int winEnd) /* handle item clicks on wikiTrack - may create new items */ { char *userName = NULL; if (wikiTrackEnabled(database, &userName) && sameWord("0", wikiItemId)) { cartWebStart(cart, database, "%s", "User Annotation Track: Create new item"); if (NULL == userName) { if (! wikiTrackReadOnly() ) /* read-only option 2012-06-25 */ { offerLogin(0, "add new items to", WIKI_TRACK_TABLE); //cartHtmlEnd(); } return; } if (emailVerified(TRUE)) /* do print message when not verified */ { outputJavaScript(); startForm("createItem", G_CREATE_WIKI_ITEM); webPrintLinkTableStart(); /* first row is a title line */ char label[256]; safef(label, ArraySize(label), "Create new item, owner: '%s'\n", userName); webPrintWideLabelCell(label, 2); webPrintLinkTableNewRow(); /* third row is position entry box */ webPrintWideCellStart(2, HG_COL_TABLE); puts("position: "); savePosInTextBox(seqName, winStart+1, winEnd); hPrintf(" (size: "); printLongWithCommas(stdout, (long long)(winEnd - winStart)); hPrintf(")"); webPrintLinkCellEnd(); webPrintLinkTableNewRow(); /* fourth row is strand selection radio box */ webPrintWideCellStart(2, HG_COL_TABLE); char *strand = cartUsualString(cart, NEW_ITEM_STRAND, "plus"); boolean plusStrand = sameWord("plus",strand) ? TRUE : FALSE; hPrintf("strand: "); cgiMakeRadioButton(NEW_ITEM_STRAND, "plus", plusStrand); hPrintf(" +  "); cgiMakeRadioButton(NEW_ITEM_STRAND, "minus", ! plusStrand); hPrintf(" -"); webPrintLinkCellEnd(); webPrintLinkTableNewRow(); /* fifth row is item name text entry */ webPrintWideCellStart(2, HG_COL_TABLE); hPrintf("item name: "); cgiMakeTextVar("i", NEW_ITEM_NAME, 18); webPrintLinkCellEnd(); #ifdef NOT webPrintLinkTableNewRow(); /* sixth row is item score text entry */ webPrintWideCellStart(2, HG_COL_TABLE); hPrintf("item score: "); cgiMakeTextVar(NEW_ITEM_SCORE, ITEM_SCORE_DEFAULT, 4); hPrintf(" (range: 0 to %s)", ITEM_SCORE_DEFAULT); webPrintLinkCellEnd(); #endif webPrintLinkTableNewRow(); /* seventh row is item color pull-down menu */ webPrintWideCellStart(2, HG_COL_TABLE); hPrintf("item color: "); colorMenuOutput(); webPrintLinkCellEnd(); webPrintLinkTableNewRow(); /* seventh row is initial comment/description text entry */ webPrintWideCellStart(2, HG_COL_TABLE); hPrintf("initial comments/description:
"); cgiMakeTextArea(NEW_ITEM_COMMENT, NEW_ITEM_COMMENT_DEFAULT, 5, 70); webPrintLinkCellEnd(); webPrintLinkTableNewRow(); /* seventh row is the submit and cancel buttons */ /*webPrintLinkCellStart(); more careful explicit alignment */ hPrintf("", HG_COL_TABLE); cgiMakeButton("submit", "create new item"); hPrintf("\n\n"); webPrintLinkCellEnd(); /*webPrintLinkCellStart(); doesn't valign center properly */ hPrintf("", HG_COL_TABLE); hPrintf("\n
", hgTracksName()); cgiMakeButton("cancel", "cancel"); hPrintf("\n
\n"); webPrintLinkCellEnd(); webPrintLinkTableEnd(); hPrintf("This entry form starts the comments for this new item.
\n" "Subsequent edits will be performed in the wiki editing system." "
\n"); webIncludeHelpFile("wikiTrackCreateItemHelp", TRUE); webIncludeHelpFile("wikiTrack", TRUE); } } else { struct wikiTrack *item = findWikiItemId(wikiItemId); cartWebStart(cart, database, "%s (%s) %s", "User Annotation Track", item->name, wikiItemId); /* if we can get the hgc clicks to add item id to the incoming data, * then use that item Id here */ displayItem(item, userName); } } /* void doWikiTrack() */ static void updateLastModifiedDate(int id) /* set lastModifiedDate to now() */ { char query[512]; struct sqlConnection *wikiConn = wikiConnect(); safef(query, ArraySize(query), "UPDATE %s set lastModifiedDate=now() WHERE id='%d'", WIKI_TRACK_TABLE, id); sqlUpdate(wikiConn,query); wikiDisconnect(&wikiConn); } static void deleteItem(int id) /* delete the item with specified id */ { char query[512]; struct sqlConnection *wikiConn = wikiConnect(); safef(query, ArraySize(query), "DELETE FROM %s WHERE id='%d'", WIKI_TRACK_TABLE, id); sqlUpdate(wikiConn,query); wikiDisconnect(&wikiConn); } void doDeleteWikiItem(char *wikiItemId, char *chrom, int winStart, int winEnd) /* handle delete item clicks for wikiTrack */ { char *userName = NULL; struct wikiTrack *item = findWikiItemId(wikiItemId); cartWebStart(cart, database, "%s (%s)", "User Annotation Track, deleted item: ", item->name); if (NULL == wikiItemId) errAbort("delete wiki item: NULL wikiItemId"); if (! wikiTrackEnabled(database, &userName)) errAbort("delete wiki item: wiki track not enabled"); /* this may be a multiple loci gene symbol annotation */ struct bed *itemList = multipleItems(item); char comments[1024]; if (slCount(itemList) > 0) safef(comments,ArraySize(comments), "This item '''%s''' on assembly %s " "at %s:%d-%d (and %d other loci) has been deleted from the wiki track\n\n", item->name, item->db, item->chrom, item->chromStart, item->chromEnd, slCount(itemList)); else safef(comments,ArraySize(comments), "This item '''%s''' on assembly %s " "at %s:%d-%d has been deleted from the wiki track\n\n", item->name, item->db, item->chrom, item->chromStart, item->chromEnd); prefixComments(item, comments, userName, seqName, winStart, winEnd, database, NULL, "(deleted item)", NEW_ITEM_CATEGORY); deleteItem(sqlSigned(wikiItemId)); /* this may be a multiple loci gene symbol annotation */ if (slCount(itemList) > 0) { struct bed *el; for (el = itemList; el; el = el->next) deleteItem(el->score); } hPrintf("
\n"); hPrintf("
", hgTracksName()); cgiMakeButton("submit", "return to tracks display"); hPrintf("\n
\n"); hPrintf("
\n"); webIncludeHelpFile("wikiTrack", TRUE); } void doAddWikiComments(char *wikiItemId, char *chrom, int winStart, int winEnd) /* handle add comment item clicks for wikiTrack */ { char *userName = NULL; struct wikiTrack *item = findWikiItemId(wikiItemId); cartWebStart(cart, database, "%s (%s)", "User Annotation Track", item->name); if (NULL == wikiItemId) errAbort("add wiki comments: NULL wikiItemId"); if (! wikiTrackEnabled(database, &userName)) errAbort("add wiki comments: wiki track not enabled"); if (NULL == userName) errAbort("add wiki comments: user not logged in ?"); addDescription(item, userName, seqName, winStart, winEnd, cart, database, NULL, NULL, NEW_ITEM_CATEGORY); updateLastModifiedDate(sqlSigned(wikiItemId)); displayItem(item, userName); } void doCreateWikiItem(char *itemName, char *chrom, int winStart, int winEnd) /* handle create item clicks for wikiTrack */ { int itemStart = 0; int itemEnd = 0; char *chrName = NULL; char *pos = NULL; char *strand = cartUsualString(cart, NEW_ITEM_STRAND, "plus"); char *class = cartUsualString(cart, NEW_ITEM_CLASS, ITEM_NOT_CLASSIFIED); boolean plusStrand = sameWord("plus",strand) ? TRUE : FALSE; char descriptionKey[256]; struct sqlConnection *wikiConn = wikiConnect(); char *userName = NULL; char *color = cartUsualString(cart, NEW_ITEM_COLOR, "#000000"); int score = 0; struct wikiTrack *newItem; if (! wikiTrackEnabled(database, &userName)) errAbort("create new wiki item: wiki track not enabled"); if (NULL == userName) errAbort("create new wiki item: user not logged in ?"); #ifdef NOT score = sqlSigned(cartUsualString(cart, NEW_ITEM_SCORE, ITEM_SCORE_DEFAULT)); #endif score = 0; pos = stripCommas(cartOptionalString(cart, "getDnaPos")); if (NULL == pos) errAbort("create new wiki item: called incorrectly, without getDnaPos"); hgParseChromRange(database, pos, &chrName, &itemStart, &itemEnd); if (NULL == chrName) webAbort("Wiki Annotation", "illegal chrom name entered: '%s'
\n" "Note: chrom names are case sensitive.
\n", pos); char *realChrName = hgOfficialChromName(database, chrName); if (NULL == realChrName) webAbort("Wiki Annotation", "illegal chrom name entered: '%s'
\n" "Note: chrom names are case sensitive.
\n", pos); if (itemStart > itemEnd) { int t = itemEnd; itemEnd = itemStart; itemStart = t; } safef(descriptionKey,ArraySize(descriptionKey), "GenomeAnnotation:%s-%d", database, 0); AllocVar(newItem); newItem->bin = binFromRange(itemStart, itemEnd); newItem->chrom = cloneString(realChrName); newItem->chromStart = itemStart; newItem->chromEnd = itemEnd; newItem->name = cloneString(itemName); newItem->score = score; safef(newItem->strand, sizeof(newItem->strand), "%s", plusStrand ? "+" : "-"); newItem->db = cloneString(database); newItem->owner = cloneString(userName); newItem->class = cloneString(class); newItem->color = cloneString(color); newItem->creationDate = cloneString("0"); newItem->lastModifiedDate = cloneString("0"); newItem->descriptionKey = cloneString(descriptionKey); newItem->id = 0; newItem->geneSymbol = cloneString("0"); wikiTrackSaveToDbEscaped(wikiConn, newItem, WIKI_TRACK_TABLE, 1024); int id = sqlLastAutoId(wikiConn); safef(descriptionKey,ArraySize(descriptionKey), "GenomeAnnotation:%s-%d", database, id); wikiTrackFree(&newItem); char newItemName[128]; char query[512]; if (sameWord(itemName,NEW_ITEM_NAME)) { safef(newItemName, ArraySize(newItemName), "%s-%d", database, id); safef(query, ArraySize(query), "UPDATE %s set creationDate=now(),lastModifiedDate=now(),descriptionKey='%s',name='%s-%d' WHERE id='%d'", WIKI_TRACK_TABLE, descriptionKey, database, id, id); } else { safef(newItemName, ArraySize(newItemName), "%s", itemName); safef(query, ArraySize(query), "UPDATE %s set creationDate=now(),lastModifiedDate=now(),descriptionKey='%s' WHERE id='%d'", WIKI_TRACK_TABLE, descriptionKey, id); } sqlUpdate(wikiConn,query); wikiDisconnect(&wikiConn); cartWebStart(cart, database, "%s %s", "User Annotation Track, created new item: ", newItemName); char wikiItemId[64]; safef(wikiItemId,ArraySize(wikiItemId),"%d", id); struct wikiTrack *item = findWikiItemId(wikiItemId); addDescription(item, userName, seqName, winStart, winEnd, cart, database, NULL, NULL, NEW_ITEM_CATEGORY); displayItem(item, userName); } /* void doCreateWikiItem() */