/* qaPushQ - Push Queue cgi */ /* we don't use the cart, we have our own table to store cart-like info */ #include #include #include #include #include #include "common.h" #include "cheapcgi.h" #include "htmshell.h" #include "jksql.h" #include "hgConfig.h" #include "obscure.h" #include "portable.h" #include "pushQ.h" #include "formPushQ.h" #include "versionInfo.h" /* stuff to support outputting Release Log html */ #include "web.h" #include "hui.h" #include "dbDb.h" #include "htmlPage.h" char msg[2048] = ""; char ** saveEnv; #define BLSIZE 512000 /* size of strings for processing big lists of tables and files */ #define BUFMAX 512000 char html[BUFMAX]; char *action = NULL; /* have to put declarations first */ boolean crossPost = FALSE; /* are we doing cross-post from dev to beta (or vice versa)? */ /* support showSizes across machines */ char *database = NULL; char *host = NULL; char *user = NULL; char *password = NULL; struct sqlConnection *conn = NULL; struct sqlConnection *conn2 = NULL; char *qaUser = NULL; #define SSSZ 256 /* MySql String Size 255 + 1 */ #define MAXBLOBSHOW 128 #define TITLE "Push Queue v"CGI_VERSION time_t curtime; struct tm *loctime; struct utsname utsName; struct users myUser; char *showColumns = NULL; char *defaultColumns = "pqid,qid,priority,importance,qadate,track,dbs,tbls,cgis,files,currLoc,makeDocYN,onlineHelp,ndxYN,stat,sponsor,reviewer,extSource,notes"; char *newRandState = NULL; char *oldRandState = NULL; /* "qid,pqid,priority,rank,qadate,newYN,track,dbs,tbls,cgis,files,sizeMB,currLoc," "makeDocYN,onlineHelp,ndxYN,joinerYN,stat,sponsor,reviewer,extSource,openIssues,notes," pushState,initdate,bounces,lockUser,lockDateTime,releaseLog,featureBits,releaseLogUrl,importance"; */ /* structural improvements suggested by MarkD: static struct { enum colEnum col; char *name; char *hdr; } colTbl [] = { {e_qid, "qid"}, {0, NULL}, } ArraySize(colTbl) numWords = chopString(liststr, ",", NULL, NULL); */ static char const *colName[] = { "qid" , "pqid" , "priority" , "rank" , "qadate" , "newYN" , "track" , "dbs" , "tbls" , "cgis" , "files" , "sizeMB" , "currLoc" , "makeDocYN" , "onlineHelp", "ndxYN" , "joinerYN" , "stat" , "featureBits", "sponsor" , "reviewer" , "extSource" , "openIssues", "notes" , "pushState" , "initdate" , "lastdate" , "bounces" , "lockUser" , "lockDateTime", "releaseLog", "releaseLogUrl", "importance" }; enum colEnum { e_qid , e_pqid , e_priority , e_rank , e_qadate , e_newYN , e_track , e_dbs , e_tbls , e_cgis , e_files , e_sizeMB , e_currLoc , e_makeDocYN , e_onlineHelp, e_ndxYN , e_joinerYN , e_stat , e_featureBits, e_sponsor , e_reviewer , e_extSource , e_openIssues, e_notes , e_pushState , e_initdate , e_lastdate , e_bounces , e_lockUser , e_lockDateTime, e_releaseLog, e_releaseLogUrl, e_importance, e_NUMCOLS }; char *colHdr[] = { "Queue ID", "Parent Queue ID", "Priority", "Rank", "    Date    ", "New?", "Track", "Databases", "Tables", "CGIs", "Files", "Size MB", "Current Location", "MakeDoc", "Online help", "Index", "All. Joiner", "          Status          ", "Feature Bits", "Sponsor (local)", "Reviewer", "External Source or Collaborator", "Open Issues", "              Notes              ", "PushState", "Initial   Submission   Date", "Last   QA   Date", "Bounce Count", "Lock User", "Lock Date Time", "Release Log", "Release Log Url", "Importance" }; char *numberToMonth[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; char pushQtbl[256] = "pushQ"; /* default */ char month[256] = ""; enum colEnum colOrder[e_NUMCOLS]; int numColumns = 0; int randInt(int N) /* generate random number from 0 to N-1 */ { return (int) N * (rand() / (RAND_MAX + 1.0)); } char *randDigits(int length) /* generate string of random digits 0-9. String will need to be free'd later. */ { int i = 0; char *s = needMem(length+1); for(i=0;i 2100) return FALSE; if ( mm > 12 ) return FALSE; if ( mm < 1 ) return FALSE; if ( dd > 31 ) return FALSE; if ( dd < 1 ) return FALSE; return TRUE; } void encryptPWD(char *password, char *salt, char *buf, int bufsize) /* encrypt a password */ { /* encrypt user's password. */ safef(buf,bufsize,crypt(password, salt)); } void encryptNewPWD(char *password, char *buf, int bufsize) /* encrypt a new password */ { unsigned long seed[2]; char salt[] = "$1$........"; const char *const seedchars = "./0123456789ABCDEFGHIJKLMNOPQRST" "UVWXYZabcdefghijklmnopqrstuvwxyz"; int i; /* Generate a (not very) random seed. */ seed[0] = time(NULL); seed[1] = getpid() ^ (seed[0] >> 14 & 0x30000); /* Turn it into printable characters from `seedchars'. */ for (i = 0; i < 8; i++) salt[3+i] = seedchars[(seed[i/5] >> (i%5)*6) & 0x3f]; encryptPWD(password, salt, buf, bufsize); } bool checkPWD(char *password, char *encPassword) /* check an encrypted password */ { char encPwd[35] = ""; encryptPWD(password, encPassword, encPwd, sizeof(encPwd)); if (sameString(encPassword,encPwd)) { return TRUE; } else { return FALSE; } } void doMsg() /* callable from htmShell */ { printf("%s",msg); } bool mySqlGetLock(char *name, int timeout) /* Tries to acquire (for 10 seconds) and set an advisory lock. * note: mysql returns 1 if successful, * 0 if name already locked or NULL if error occurred * blocks another client from obtaining a lock with the same name * lock is automatically released by mysql when connection is closed or detected broken * may even detect program crash and release lock. */ { char query[256]; struct sqlResult *rs; char **row = NULL; bool result = FALSE; safef(query, sizeof(query), "select get_lock('%s', %d)", name, timeout); rs = sqlGetResult(conn, query); row=sqlNextRow(rs); if (row[0] == NULL) { safef(msg, sizeof(msg), "Attempt to GET_LOCK of %s caused an error\n",name); htmShell(TITLE, doMsg, NULL); exit(0); } if (sameWord(row[0], "1")) result = TRUE; else if (sameWord(row[0], "0")) result = FALSE; sqlFreeResult(&rs); return result; } void mySqlReleaseLock(char *name) /* Releases an advisory lock created by GET_LOCK in mySqlGetLock */ { char query[256]; safef(query, sizeof(query), "select release_lock('%s')", name); sqlUpdate(conn, query); } void setLock() /* set a lock to reduce concurrency problems */ { mySqlGetLock("qapushq",10); /* just an advisory semaphore, really */ } void releaseLock() /* release the advisory lock */ { mySqlReleaseLock("qapushq"); } enum colEnum mapFieldToEnum(char *f, bool must) { int i = 0; for(i=0;i= ssize) { errAbort("buf size exceeded. strlen(temp)=%ld, size of buf= %d",(unsigned long)strlen(temp),ssize); } safef(s,ssize,"%s",temp); freez(&temp); } bool parseList(char *s, char delim, int num, char *buf, int bufsize) /* parse list to find nth element of delim-separated list in string * returns l if not found which points to the string end 0 * otherwise returns offset in s where begins */ { int n = 0; int i = 0; int l = strlen(s); int j = 0; char c; if (bufsize==0) { return FALSE; } while (TRUE) { if (n==num) { while (j= l) { buf[0] = 0; return FALSE; } i++; } i++; n++; } } void replaceSelectOptions(char *varname, char *values, char *value) /* Replace tags in select option picklist. * This initializes the correct default selection. * Currently values is a list of single characters only, * picklists with string-values not supported. */ { int i = 0; char *p = NULL; char tempTag[256] = ""; char tempVal[256]; while(TRUE) { parseList(values,',',i,tempVal,sizeof(tempVal)); if (tempVal[0]==0) { break; } safef(tempTag,sizeof(tempTag),"",varname,tempVal); if (sameString(value,tempVal)) {p = "selected";} else {p = "";} replaceInStr(html, sizeof(html), tempTag, p); i++; } } void initColsFromString() { int i = 0, e=0; char colName[256]; char sep[2]=""; struct dyString * s = NULL; s = newDyString(2048); /* need room */ numColumns=0; while(parseList(showColumns,',',i,colName,sizeof(colName))) { e = mapFieldToEnum(colName,FALSE); if (e >= 0) /* tolerate old nonexistent colnames in pseudocart more gracefully */ { colOrder[i] = e; dyStringPrintf(s, "%s%s", sep, colName); safef(sep,sizeof(sep),","); numColumns++; } i++; } showColumns = cloneString(s->string); freeDyString(&s); } /* -------------------- Push Queue ----------------------- */ void showSizesJavascript() /* set showSizes for cross-posting to support file sizes */ { char sizesButton[1024]; safef(sizesButton, sizeof(sizesButton), "     " , utsName.nodename , sameString(utsName.nodename, "hgwdev") ? "hgwbeta" : "hgwdev" ); replaceInStr(html, sizeof(html), "", sizesButton); } void replacePushQFields(struct pushQ *ki, bool isNew) /* fill in dummy html tags with values from the sql pushQ record */ { char tempLink[256]; char tempSizeMB[256]; char tempMsg[256]; bool myLock = FALSE; if (sameString(ki->lockUser,qaUser)) { myLock = TRUE; } safef(html,sizeof(html),"%s",formQ); safef(tempSizeMB, sizeof(tempSizeMB), "%u", ki->sizeMB); if (ki->sizeMB == 0) { safef(tempSizeMB,sizeof(tempSizeMB),"%s",""); } replaceInStr(html, sizeof(html) , "" , ki->qid ); replaceSelectOptions("priority" , "A,B,C,D,L" , ki->priority ); replaceInStr(html, sizeof(html) , "" , ki->qadate ); replaceSelectOptions("newYN" ,"Y,N,X" , ki->newYN ); replaceInStr(html, sizeof(html) , "" , ki->track ); replaceInStr(html, sizeof(html) , "" , ki->dbs ); replaceInStr(html, sizeof(html) , "" , ki->tbls ); replaceInStr(html, sizeof(html) , "" , ki->cgis ); replaceInStr(html, sizeof(html) , "" , ki->files ); replaceInStr(html, sizeof(html) , "" , tempSizeMB ); replaceInStr(html, sizeof(html) , "" , ki->currLoc ); replaceSelectOptions("currLoc" , "hgwdev,hgwbeta" , ki->currLoc ); replaceSelectOptions("makeDocYN", "Y,N,X" , ki->makeDocYN ); replaceInStr(html, sizeof(html) , "" , ki->onlineHelp); replaceSelectOptions("ndxYN" , "Y,N,X" , ki->ndxYN ); replaceSelectOptions("joinerYN" , "Y,N,X" , ki->joinerYN ); replaceInStr(html, sizeof(html) , "" , ki->stat ); replaceInStr(html, sizeof(html) , "" , ki->featureBits); replaceInStr(html, sizeof(html) , "" , ki->sponsor ); replaceInStr(html, sizeof(html) , "" , ki->reviewer ); replaceInStr(html, sizeof(html) , "" , ki->extSource ); replaceInStr(html, sizeof(html) , "" , ki->openIssues); replaceInStr(html, sizeof(html) , "" , ki->notes ); replaceInStr(html, sizeof(html) , "" , ki->initdate ); replaceInStr(html, sizeof(html) , "" , ki->releaseLog); replaceInStr(html, sizeof(html) , "", ki->releaseLogUrl); replaceSelectOptions("importance", " ,B,L,M,H,U" , ki->importance ); replaceInStr(html, sizeof(html) , "" , newRandState ); if (isNew) { replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", "  "); replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", ""); safef(tempLink, sizeof(tempLink), "CANCEL  ",newRandState); replaceInStr(html, sizeof(html), "", tempLink ); showSizesJavascript(); } else { if (myLock) { replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", "  "); replaceInStr(html, sizeof(html), "" , "  "); if (ki->priority[0]!='L') { replaceInStr(html, sizeof(html), "", "" "  "); } replaceInStr(html, sizeof(html), "", "  "); if (ki->priority[0]=='A') { replaceInStr(html, sizeof(html), "", "  "); } else { replaceInStr(html, sizeof(html), "", "" "  "); } replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", "  "); replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", "  "); showSizesJavascript(); } else { /* we don't have a lock yet, disable and readonly */ replaceInStr(html, sizeof(html), "", "DISABLED"); replaceInStr(html, sizeof(html), "", "READONLY"); replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", "  "); safef(tempLink, sizeof(tempLink), "RETURN  ",newRandState); replaceInStr(html, sizeof(html), "", tempLink ); safef(tempLink, sizeof(tempLink), "REFRESH  ", ki->qid,newRandState); replaceInStr(html, sizeof(html), "", tempLink ); replaceInStr(html, sizeof(html), "", ""); replaceInStr(html, sizeof(html), "", ""); if (sameString(ki->lockUser,"")) { safef(tempMsg,sizeof(tempMsg),"%s %s", msg, "READONLY view. Press Lock to edit. Click RETURN for the main queue."); } else { safef(tempMsg,sizeof(tempMsg),"%s User %s currently has lock on Queue Id %s since %s.", msg, ki->lockUser, ki->qid,ki->lockDateTime ); } safef(msg,sizeof(msg), "%s", tempMsg); } } replaceInStr(html, sizeof(html) , "" , msg ); safef(msg,sizeof(msg),"%s",""); printf("%s",html); } void doAdd() /* handle setup add form for new pushQ record */ { struct pushQ q; ZeroVar(&q); q.next = NULL; safef(q.qid, sizeof(q.qid), "%s", ""); safef(q.priority, sizeof(q.priority), "%s", "A"); /* default priority */ strftime (q.qadate, sizeof(q.qadate), "%Y-%m-%d", loctime); /* default to today's date */ safef(q.newYN, sizeof(q.newYN), "%s", "N"); /* default to not new track */ q.track = ""; q.dbs = ""; q.tbls = ""; q.cgis = ""; q.files = ""; q.sizeMB = 0; safef(q.currLoc , sizeof(q.currLoc) , "%s", "hgwdev"); /* default loc */ safef(q.makeDocYN , sizeof(q.makeDocYN) , "%s", "N"); safef(q.onlineHelp, sizeof(q.onlineHelp), "%s", "" ); safef(q.ndxYN , sizeof(q.ndxYN) , "%s", "N"); /* default to not checked yet */ safef(q.joinerYN , sizeof(q.joinerYN) , "%s", "N"); /* default to all.joiner not checked yet */ q.stat = ""; q.featureBits = ""; safef(q.sponsor , sizeof(q.sponsor) , "%s", "" ); safef(q.reviewer , sizeof(q.reviewer) , "%s", "" ); if (sameString(myUser.role,"qa")) { safef(q.reviewer, sizeof(q.reviewer), "%s", qaUser); /* if role is qa, default reviewer to this user */ } if (sameString(myUser.role,"dev")) { safef(q.sponsor , sizeof(q.sponsor) , "%s", qaUser); /* if role is dev, default sponsor to current user */ } safef(q.extSource , sizeof(q.extSource) , "%s", "" ); q.openIssues = ""; q.notes = ""; strftime (q.initdate, sizeof(q.initdate), "%Y-%m-%d", loctime); /* automatically use today date */ safef(q.lastdate, sizeof(q.lastdate), "%s", "" ); q.releaseLog = ""; q.releaseLogUrl = ""; safef(q.importance, sizeof(q.importance), "%s", " "); /* default importance */ if (sameString(myUser.role,"dev")) { safef(msg, sizeof(msg), "%s", "Developer: Please leave priority and date alone. " "Do specify if the track is new. Enter the shortLabel for the track name. " "Be sure to fill out the database, tables, and external files, if any. " "If relevant cgis have changed since last branch, please list them. " "Enter collaborator if applicable. " "Leave the other fields for QA. You may leave a note for QA staff in the notes field. " "Thanks very much!" ); } replacePushQFields(&q, TRUE); /* new rec = true */ } void dotdotdot(char *s, int l) /* truncate a string for shorter display with ... at end */ { if ((strlen(s) before \n to have an effect inside html */ { return replaceChars(s,"\n","
\n"); } void drawDisplayLine(enum colEnum col, struct pushQ *ki) { char *temp = NULL; switch(col) { case e_qid: printf("%s%s", ki->qid, newRandState, ki->qid, sameString(ki->lockUser,"") ? "":"*" ); if (ki->pushState[0]=='Y') { printf("
Done!", ki->qid, newRandState ); } printf("\n"); break; case e_pqid: printf("%s\n", ki->pqid ); break; case e_priority: if (ki->priority[0] == 'L') { printf("%s", ki->priority); } else { printf( "
%s" "^  " "T  " "
 " "v  " "B" "
\n", ki->priority, ki->qid, newRandState, ki->qid, newRandState, ki->qid, newRandState, ki->qid, newRandState ); } break; case e_rank: printf("%d\n", ki->rank ); break; case e_qadate: printf("%s\n", ki->qadate ); break; case e_newYN: printf("%s\n", ki->newYN ); break; case e_track: dotdotdot(ki->track,MAXBLOBSHOW); /* chr(255) */ printf("%s\n", ki->track ); break; case e_dbs: dotdotdot(ki->tbls ,MAXBLOBSHOW); /* chr(255) */ printf("%s\n", ki->dbs ); break; case e_tbls: dotdotdot(ki->tbls,MAXBLOBSHOW); /* longblob */ printf("%s\n", ki->tbls ); break; case e_cgis: dotdotdot(ki->cgis ,MAXBLOBSHOW); /* chr(255) */ printf("%s\n", ki->cgis ); break; case e_files: dotdotdot(ki->files,MAXBLOBSHOW); /* chr(255) */ printf("%s\n", fixLineBreaks(ki->files) ); break; case e_sizeMB: printf("%u\n", ki->sizeMB ); break; case e_currLoc: printf("%s\n", ki->currLoc ); break; case e_makeDocYN: printf("%s\n", ki->makeDocYN ); break; case e_onlineHelp: printf("%s\n", ki->onlineHelp); break; case e_ndxYN: printf("%s\n", ki->ndxYN ); break; case e_joinerYN: printf("%s\n", ki->joinerYN ); break; case e_stat: dotdotdot(ki->stat ,MAXBLOBSHOW); /* chr(255) */ printf("%s\n", ki->stat ); break; case e_featureBits: dotdotdot(ki->featureBits,MAXBLOBSHOW); /* longblob */ printf("%s\n", ki->featureBits); break; case e_sponsor: printf("%s\n", ki->sponsor ); break; case e_reviewer: printf("%s\n", ki->reviewer ); break; case e_extSource: printf("%s\n", ki->extSource ); break; case e_openIssues: dotdotdot(ki->openIssues,MAXBLOBSHOW); /* longblob */ printf("%s\n", ki->openIssues); break; case e_notes: dotdotdot(ki->notes,MAXBLOBSHOW); /* longblob */ printf("%s\n", ki->notes ); break; case e_pushState: printf("%s\n", ki->pushState); break; case e_initdate: printf("%s\n", ki->initdate ); break; case e_lastdate: printf("%s\n", ki->lastdate ); break; case e_bounces: printf("%u\n", ki->bounces ); break; case e_lockUser: printf("%s\n", ki->lockUser ); break; case e_lockDateTime: printf("%s\n", ki->lockDateTime ); break; case e_releaseLog: dotdotdot(ki->releaseLog,MAXBLOBSHOW); /* chr(255) */ printf("%s\n", ki->releaseLog ); break; case e_releaseLogUrl: dotdotdot(ki->releaseLogUrl,MAXBLOBSHOW); /* chr(255) */ printf("%s\n", ki->releaseLogUrl ); break; case e_importance: temp = ""; if (sameString(ki->importance, "") || sameString(ki->importance, " ")) temp = "Unprioritized"; else if (sameString(ki->importance, "B")) temp = "Background"; else if (sameString(ki->importance, "L")) temp = "Low"; else if (sameString(ki->importance, "M")) temp = "Medium"; else if (sameString(ki->importance, "H")) temp = "High"; else if (sameString(ki->importance, "U")) temp = "Urgent"; printf("%s\n", temp ); break; default: errAbort("drawDisplayLine: unexpected case enum %d.",col); } } void doDisplay() /* handle display request, shows pushQ records, also this is the default action */ { struct pushQ *ki, *kiList = NULL; struct sqlResult *sr; char **row; char query[256]; char lastP = ' '; int c = 0; char monthsql[256]; char comment[256]; /* initialize column display order */ initColsFromString(); safef(monthsql,sizeof(monthsql),"%s",""); if (!sameString(month,"")) { safef(monthsql,sizeof(monthsql)," where priority='L' and qadate like '%s%%' ",month); } /* Get a list of all (or in month). */ safef(query, sizeof(query), "select * from %s%s%s", pushQtbl, monthsql, " order by priority, rank, qadate desc, qid desc limit 200" ); sr = sqlGetResult(conn, query); while ((row = sqlNextRow(sr)) != NULL) { ki = pushQLoad(row); slAddHead(&kiList, ki); } sqlFreeResult(&sr); slReverse(&kiList); /* #rows returned slCount(kiList) */ if (sameString(utsName.nodename,"hgwdev")) { printf("

Machine: %s THIS IS NOT THE REAL PUSHQ- GO TO HGWBETA

\n",utsName.nodename); } if (!sameString(msg,"")) { printf("

%s

\n",msg); } if (sameString(month,"")) { printf(" ADD\n",newRandState); } else { printf(" Current\n",newRandState); } printf(" Logout\n",newRandState); printf(" All Columns\n",newRandState); printf(" Default Columns\n",newRandState); printf(" Log by Month\n",newRandState); printf(" Gateway\n",newRandState); printf(" Help\n"); printf(" Release Log\n"); //printf(" Publish RL\n"); printf(" A\n",newRandState); printf(" B\n",newRandState); printf(" C\n",newRandState); printf(" D\n",newRandState); printf(" L\n",newRandState); printf(" Refresh\n",newRandState); //printf(" newRandState=%s\n",newRandState); //printf(" oldRandState=%s\n",oldRandState); /* draw table header */ printf("

Track Push Queue"); if (!sameString(pushQtbl,"pushQ")) { printf(" for %s",pushQtbl); } if (!sameString(month,"")) { printf(" (%s)",month); } printf("

\n"); printf("\n"); printf(" \n"); for (c=0; c" "< " "! " ">" "
\n", colName[colOrder[c]], newRandState, colName[colOrder[c]], newRandState, colName[colOrder[c]], newRandState ); } printf("
\n"); printf(" \n"); for (c=0; c%s\n",colHdr[colOrder[c]]); } printf(" \n"); /* Print some info for each match */ for (ki = kiList; ki != NULL; ki = ki->next) { /* Major-priority section header */ if (ki->priority[0] != lastP) { lastP = ki->priority[0]; safef(comment,sizeof(comment),"%s",""); switch (ki->priority[0]) { case 'A': safef(comment,sizeof(comment),"%s","active"); break; case 'B': safef(comment,sizeof(comment),"%s","short hold"); break; case 'C': safef(comment,sizeof(comment),"%s","long hold"); break; case 'L': safef(comment,sizeof(comment),"%s","log"); break; } printf(""); printf("\n", ki->priority, ki->priority, comment); printf(""); } /* Regular row */ printf(""); for (c=0; c"); } /* draw table footer */ printf("

%s

%s
"); pushQFreeList(&kiList); } struct pushQ *loadPushQ(char *qid) /* Return pushQ struct loading q with existing values. * Use pushQFree() when done.*/ { char **row; struct sqlResult *sr; char query[256]; struct pushQ *q = NULL; safef(query, sizeof(query), "select * from %s where qid = '%s'",pushQtbl,qid); sr = sqlGetResult(conn, query); row = sqlNextRow(sr); if (row) q = pushQLoad(row); sqlFreeResult(&sr); return q; } struct pushQ *mustLoadPushQ(char *qid) /* Load pushQ or die */ { struct pushQ *q = loadPushQ(qid); if (!q) errAbort("loadPushQ: Queue Id %s not found.",qid); return q; } void doPushDone() /* Mark record pushState=D, move priority to L for Log, and set rank=0 */ { struct pushQ *q; char query[256]; q=mustLoadPushQ(cgiString("qid")); if (sameString(q->lockUser,"") && sameString(q->pushState,"Y")) { /* not already locked and pushState=Y */ safef(q->lastdate, sizeof(q->lastdate), q->qadate); strftime (q->qadate , sizeof(q->qadate ), "%Y-%m-%d", loctime); /* today's date */ safef(query, sizeof(query), "update %s set rank = 0, priority ='L', pushState='D', qadate='%s', lastdate='%s' " "where qid = '%s' ", pushQtbl, q->qadate, q->lastdate, q->qid); sqlUpdate(conn, query); /* first close the hole where it was */ safef(query, sizeof(query), "update %s set rank = rank - 1 where priority ='%s' and rank > %d ", pushQtbl, q->priority, q->rank); sqlUpdate(conn, query); } else { if (sameString(q->lockUser,"")) { safef(msg, sizeof(msg), "Unable to mark record %s done-> Record is locked by %s->",q->qid,q->lockUser); } else { safef(msg, sizeof(msg), "Invalid operation for qid %s, pushState is not Y, = %s->",q->qid,q->pushState); } } pushQFree(&q); doDisplay(); } void XdoPromote(int change) /* Promote the ranking of this Q item * >0 means promote, <0 means demote */ { struct pushQ *q; char query[256]; char newQid[sizeof(q->qid)] = ""; safef(newQid, sizeof(newQid), cgiString("qid")); q = mustLoadPushQ(newQid); if ((q->rank > 1) && (change>0)) { /* swap places with rank-1 */ safef(query, sizeof(query), "update %s set rank = rank + 1 where priority ='%s' and rank = %d ", pushQtbl, q->priority, q->rank-1); sqlUpdate(conn, query); q->rank--; safef(query, sizeof(query), "update %s set rank = %d where qid ='%s'", pushQtbl, q->rank, q->qid); sqlUpdate(conn, query); } if (change<0) { /* swap places with rank+1 */ safef(query, sizeof(query), "update %s set rank = rank - 1 where priority ='%s' and rank = %d ", pushQtbl, q->priority, q->rank+1); if (sqlUpdateRows(conn, query, NULL)>0) { q->rank++; safef(query, sizeof(query), "update %s set rank = %d where qid ='%s'", pushQtbl, q->rank, q->qid); sqlUpdate(conn, query); } } pushQFree(&q); doDisplay(); } void doPromote() { XdoPromote(1); } void doDemote() { XdoPromote(-1); } int getNextAvailQid() /* adding new pushQ rec, get next available qid number */ { struct pushQ q; int newqid = 0; char query[256]; char *quickres = NULL; safef(query, sizeof(query), "select max(qid) from %s",pushQtbl); quickres = sqlQuickString(conn, query); if (quickres != NULL) { safef(q.qid, sizeof(q.qid), quickres); sscanf(q.qid,"%d",&newqid); freez(&quickres); } newqid++; return newqid; } int getNextAvailRank(char *priority) /* get next available rank at end of priority section */ { struct pushQ q; char query[256]; char *quickres = NULL; safef(query, sizeof(query), "select rank from %s where priority='%s' order by rank desc limit 1", pushQtbl, priority); quickres = sqlQuickString(conn, query); if (quickres == NULL) { q.rank = 0; } else { sscanf(quickres,"%d",&q.rank); freez(&quickres); } q.rank++; return q.rank; } void doTop() { struct pushQ *q; char query[256]; char newQid[sizeof(q->qid)] = ""; safef(newQid, sizeof(newQid), cgiString("qid")); q = mustLoadPushQ(newQid); /* first close the hole where it was */ safef(query, sizeof(query), "update %s set rank = rank + 1 where priority ='%s' and rank < %d ", pushQtbl, q->priority, q->rank); sqlUpdate(conn, query); q->rank = 1; safef(query, sizeof(query), "update %s set rank = %d where qid = '%s' ", pushQtbl, q->rank, q->qid); sqlUpdate(conn, query); pushQFree(&q); doDisplay(); } void doBottom() { struct pushQ *q; char query[256]; char newQid[sizeof(q->qid)] = ""; safef(newQid, sizeof(newQid), cgiString("qid")); q = mustLoadPushQ(newQid); /* first close the hole where it was */ safef(query, sizeof(query), "update %s set rank = rank - 1 where priority ='%s' and rank > %d ", pushQtbl, q->priority, q->rank); sqlUpdate(conn, query); q->rank = getNextAvailRank(q->priority); safef(query, sizeof(query)," update %s set rank = %d where qid = '%s' ", pushQtbl, q->rank, q->qid); sqlUpdate(conn, query); pushQFree(&q); doDisplay(); } /* too bad this isn't part of autoSql's code generation */ void pushQUpdateEscaped(struct sqlConnection *conn, struct pushQ *el, char *tableName, int updateSize) /* Update pushQ row to the table specified by tableName. * As blob fields may be arbitrary size updateSize specifies the approx size. * of a string that would contain the entire query. Automatically * escapes all simple strings (not arrays of string) but may be slower than pushQSaveToDb(). * For example automatically copies and converts: * "autosql's features include" --> "autosql\'s features include" * before inserting into database. */ { struct dyString *update = newDyString(updateSize); char *qid, *pqid, *priority, *qadate, *newYN, *track, *dbs, *tbls, *cgis, *files, *currLoc, *makeDocYN, *onlineHelp, *ndxYN, *joinerYN, *stat, *featureBits, *sponsor, *reviewer, *extSource, *openIssues, *notes, *pushState, *initdate, *lastdate, *lockUser, *lockDateTime, *releaseLog, *releaseLogUrl, *importance; qid = sqlEscapeString(el->qid); pqid = sqlEscapeString(el->pqid); priority = sqlEscapeString(el->priority); qadate = sqlEscapeString(el->qadate); newYN = sqlEscapeString(el->newYN); track = sqlEscapeString(el->track); dbs = sqlEscapeString(el->dbs); tbls = sqlEscapeString(el->tbls); cgis = sqlEscapeString(el->cgis); files = sqlEscapeString(el->files); currLoc = sqlEscapeString(el->currLoc); makeDocYN = sqlEscapeString(el->makeDocYN); onlineHelp = sqlEscapeString(el->onlineHelp); ndxYN = sqlEscapeString(el->ndxYN); joinerYN = sqlEscapeString(el->joinerYN); stat = sqlEscapeString(el->stat); featureBits = sqlEscapeString(el->featureBits); sponsor = sqlEscapeString(el->sponsor); reviewer = sqlEscapeString(el->reviewer); extSource = sqlEscapeString(el->extSource); openIssues = sqlEscapeString(el->openIssues); notes = sqlEscapeString(el->notes); pushState = sqlEscapeString(el->pushState); initdate = sqlEscapeString(el->initdate); lastdate = sqlEscapeString(el->lastdate); lockUser = sqlEscapeString(el->lockUser); lockDateTime = sqlEscapeString(el->lockDateTime); releaseLog = sqlEscapeString(el->releaseLog); releaseLogUrl = sqlEscapeString(el->releaseLogUrl); importance = sqlEscapeString(el->importance); /* had to split this up because dyStringPrintf only up to 4000 chars at one time */ dyStringPrintf(update, "update %s set " "pqid='%s',priority='%s',rank=%u,qadate='%s',newYN='%s',track='%s',", tableName, pqid, priority, el->rank, qadate, newYN, track); dyStringPrintf(update, "dbs='%s',",dbs); dyStringPrintf(update, "tbls='%s',",tbls); dyStringPrintf(update, "cgis='%s',",cgis); dyStringPrintf(update, "files='%s',",files); dyStringPrintf(update, "sizeMB=%u,currLoc='%s'," "makeDocYN='%s',onlineHelp='%s',ndxYN='%s',joinerYN='%s',stat='%s'," "sponsor='%s',reviewer='%s',extSource='%s',", el->sizeMB , currLoc, makeDocYN, onlineHelp, ndxYN, joinerYN, stat, sponsor, reviewer, extSource); dyStringPrintf(update, "openIssues='%s',",openIssues); dyStringPrintf(update, "notes='%s',",notes); dyStringPrintf(update, "pushState='%s', initdate='%s', lastdate='%s', bounces='%u',lockUser='%s'," "lockDateTime='%s',releaseLog='%s',featureBits='%s',releaseLogUrl='%s'," "importance='%s' where qid='%s'", pushState, initdate, lastdate, el->bounces, lockUser, lockDateTime, releaseLog, featureBits, releaseLogUrl, importance, qid ); sqlUpdate(conn, update->string); freeDyString(&update); freez(&qid); freez(&pqid); freez(&priority); freez(&qadate); freez(&newYN); freez(&track); freez(&dbs); freez(&tbls); freez(&cgis); freez(&files); freez(&currLoc); freez(&makeDocYN); freez(&onlineHelp); freez(&ndxYN); freez(&joinerYN); freez(&stat); freez(&sponsor); freez(&reviewer); freez(&extSource); freez(&openIssues); freez(¬es); freez(&pushState); freez(&initdate); freez(&lastdate); freez(&lockUser); freez(&lockDateTime); freez(&releaseLog); freez(&releaseLogUrl); freez(&importance); } void getCgiData(bool *isOK, bool isPtr, void *ptr, int size, char *name) /* get data, truncate to fit in field to prevent safef buf overflows */ { int l = 0; char **pfld = NULL; char *fld = NULL; char *cgi = NULL; cgi = cgiString(name); l = strlen(cgi); if (isPtr) { pfld = (char **) ptr; } else { fld = (char *) ptr; } if (size != -1) /* -1 for blob, has no length */ { if (l>(size-1)) { *isOK = FALSE; safef(msg,sizeof(msg),"%s: too large, max. %d chars.",name,size-1); } } if (isPtr) { *pfld = cloneString(cgi); /* set pointer to a copy of the whole thing */ } else { safef(fld, size, cloneStringZ(cgi,size-1)); /* for non-ptr strings, copy into existing buffer */ } } void doTransfer(); /* forward reference needed */ void doShowSizes(); /* forward reference needed */ void doEdit(); /* forward reference needed */ void doPost() /* handle the post (really just a get for now) from Add or Edit of a pushQ record */ { int updateSize = 2456; int newqid = 0; char query[256]; char *submitbutton = cgiUsualString("submit" ,""); char *delbutton = cgiUsualString("delbutton" ,""); char *pushbutton = cgiUsualString("pushbutton" ,""); char *clonebutton = cgiUsualString("clonebutton" ,""); char *bouncebutton = cgiUsualString("bouncebutton",""); char *lockbutton = cgiUsualString("lockbutton" ,""); char *cancelbutton = cgiUsualString("cancelbutton" ,""); char *showSizes = cgiUsualString("showSizes" ,""); char *transfer = cgiUsualString("transfer" ,""); struct pushQ *q; bool isNew = FALSE; /* new rec */ bool isRedo = FALSE; /* need to return to edit form with error msg */ bool isOK = TRUE; /* is data valid length (not too large) */ bool lockOK = TRUE; /* assume for now lock state OK */ char newQid [sizeof(q->qid)] = ""; char newPriority[sizeof(q->priority)] = ""; safef(newQid, sizeof(newQid), cgiString("qid")); if (sameString(newQid,"")) { isNew = TRUE; } else { isNew = FALSE; } if (!isNew) { /* we need to preload q with existing values * because some fields like rank are not carried in form */ q = mustLoadPushQ(newQid); /* true means optional, it was asked if we could tolerate this, * e.g. delete, then hit back-button * user is trying to use back button to recover deleted rec safef(newQid, sizeof(newQid), ""); isNew = TRUE; */ /* check lock status */ if (sameString(cancelbutton,"Cancel")) /* user cancelled */ { /* unlock record */ safef(q->lockUser, sizeof(q->lockUser), "%s", ""); safef(q->lockDateTime, sizeof(q->lockDateTime), "%s", ""); pushQUpdateEscaped(conn, q, pushQtbl, updateSize); lockOK = FALSE; } else if (sameString(lockbutton,"Lock")) /* try to lock the record for editing */ { if (sameString(q->lockUser,"")) /* q->lockUser blank if nobody has lock */ { safef(q->lockUser, sizeof(q->lockUser), qaUser); strftime(q->lockDateTime, sizeof(q->lockDateTime), "%Y-%m-%d %H:%M", loctime); pushQUpdateEscaped(conn, q, pushQtbl, updateSize); lockOK = FALSE; } else { /* somebody else has lock-> */ lockOK = FALSE; } } else if (!sameString(q->lockUser,qaUser)) /* User supposed to already have lock, verify. */ { /* if lock was lost, what do we do now? */ if (sameString(q->lockUser,"")) { safef(msg,sizeof(msg),"Lost lock-> Must refresh data->"); } else { safef(msg,sizeof(msg),"Lost lock-> User %s currently has lock on Queue Id %s since %s->", q->lockUser,q->qid,q->lockDateTime); } lockOK = FALSE; } if (!lockOK) { doEdit(); pushQFree(&q); return; } } if (isNew) { AllocVar(q); newqid = getNextAvailQid(); safef(q->pqid, sizeof(q->pqid), "%s", ""); safef(q->pushState,sizeof(q->pushState),"N"); /* default to: push not done yet */ } safef(newPriority, sizeof(newPriority), cgiString("priority")); /* dates */ getCgiData(&isOK, FALSE, q->qadate , sizeof(q->qadate ), "qadate" ); getCgiData(&isOK, FALSE, q->initdate , sizeof(q->initdate ), "initdate" ); /* YN select listboxes */ getCgiData(&isOK, FALSE, q->newYN , sizeof(q->newYN ), "newYN" ); getCgiData(&isOK, FALSE, q->makeDocYN , sizeof(q->makeDocYN ), "makeDocYN" ); getCgiData(&isOK, FALSE, q->ndxYN , sizeof(q->ndxYN ), "ndxYN" ); getCgiData(&isOK, FALSE, q->joinerYN , sizeof(q->joinerYN ), "joinerYN" ); getCgiData(&isOK, FALSE, q->importance, sizeof(q->importance), "importance" ); /* chr(255) strings */ getCgiData(&isOK, TRUE ,&q->track , 256 , "track" ); getCgiData(&isOK, TRUE ,&q->dbs , 256 , "dbs" ); getCgiData(&isOK, TRUE ,&q->cgis , 256 , "cgis" ); getCgiData(&isOK, TRUE ,&q->stat , 256 , "stat" ); /* integers */ if (sscanf(cgiString("sizeMB"),"%u",&q->sizeMB) != 1) { q->sizeMB = 0; } /* strings of various sizes */ getCgiData(&isOK, FALSE, q->currLoc , sizeof(q->currLoc ), "currLoc" ); getCgiData(&isOK, FALSE, q->onlineHelp, sizeof(q->onlineHelp), "onlineHelp"); getCgiData(&isOK, FALSE, q->sponsor , sizeof(q->sponsor ), "sponsor" ); getCgiData(&isOK, FALSE, q->reviewer , sizeof(q->reviewer ), "reviewer" ); getCgiData(&isOK, FALSE, q->extSource , sizeof(q->extSource ), "extSource" ); /* blobs */ getCgiData(&isOK, TRUE ,&q->tbls , -1 , "tbls" ); getCgiData(&isOK, TRUE ,&q->files , -1 , "files" ); getCgiData(&isOK, TRUE ,&q->featureBits, -1 , "featureBits"); getCgiData(&isOK, TRUE ,&q->openIssues, -1 , "openIssues"); getCgiData(&isOK, TRUE ,&q->notes , -1 , "notes" ); getCgiData(&isOK, TRUE ,&q->releaseLog, -1 , "releaseLog"); getCgiData(&isOK, TRUE ,&q->releaseLogUrl, -1 , "releaseLogUrl"); /* check for things too big */ if (!isOK) { isRedo = TRUE; } if ((q->sizeMB < 0) || (q->sizeMB > 100000000)) { safef(msg,sizeof(msg),"Size(MB): invalid size.
\n"); isRedo = TRUE; } if (!isDateValid(cgiString("qadate"))) { safef(msg,sizeof(msg),"Date format invalid, should be YYYY-MM-DD.
\n"); isRedo = TRUE; } if (strlen(cgiString("track"))>255) { safef(msg,sizeof(msg),"Track: too long for field, 255 char max.
\n"); isRedo = TRUE; } if (strlen(cgiString("dbs"))>255) { safef(msg,sizeof(msg),"Database: too long for field, 255 char max.
\n"); isRedo = TRUE; } if (strlen(cgiString("cgis"))>255) { safef(msg,sizeof(msg),"CGIs: too long for field, 255 char max.
\n"); isRedo = TRUE; } if (strlen(cgiString("stat"))>255) { safef(msg,sizeof(msg),"Status: too long for field, 255 char max.
\n"); isRedo = TRUE; } /* need to do this before delete or will lose the record */ if ((sameString(pushbutton,"push requested"))&&(q->sizeMB==0)) { safef(msg,sizeof(msg),"Size (MB) should not be zero.
\n"); isRedo = TRUE; } if ((sameString(pushbutton,"push requested"))&&(!sameString(q->currLoc,"hgwbeta"))) { safef(msg,sizeof(msg),"Current Location should be hgwbeta.
\n"); isRedo = TRUE; } if ((sameString(pushbutton,"push requested"))&&(sameString(q->makeDocYN,"N"))) { safef(msg,sizeof(msg),"MakeDoc not verified.
\n"); isRedo = TRUE; } if ((sameString(pushbutton,"push requested"))&&(sameString(q->ndxYN,"N"))) { safef(msg,sizeof(msg),"Index not verified.
\n"); isRedo = TRUE; } if ((sameString(pushbutton,"push requested"))&&(sameString(q->joinerYN,"N"))) { safef(msg,sizeof(msg),"All->Joiner not verified.
\n"); isRedo = TRUE; } if ((sameString(bouncebutton,"bounce"))&&(!sameString(q->priority,"A"))) { safef(msg,sizeof(msg),"Only priority A records should be bounced.
\n"); isRedo = TRUE; } if ((sameString(bouncebutton,"unbounce"))&&(sameString(q->priority,"A"))) { safef(msg,sizeof(msg),"Priority A records should not be unbounced.
\n"); isRedo = TRUE; } if (isRedo) { replacePushQFields(q, isNew); pushQFree(&q); return; } if (sameString(bouncebutton,"bounce")) { safef(newPriority, sizeof(newPriority), "B"); safef(q->lastdate, sizeof(q->lastdate), q->qadate); strftime (q->qadate, sizeof(q->qadate), "%Y-%m-%d", loctime); /* set to today's date */ q->bounces++; } if (sameString(bouncebutton,"unbounce")) { safef(newPriority, sizeof(newPriority), "A"); safef(q->lastdate, sizeof(q->lastdate), q->qadate); strftime (q->qadate, sizeof(q->qadate), "%Y-%m-%d", loctime); /* set to today's date */ } /* check if priority class has changed, or deleted, then close ranks */ if ( (!sameString(newPriority,q->priority)) || (sameString(delbutton,"delete")) ) { /* first close the hole where it was */ safef(query, sizeof(query), "update %s set rank = rank - 1 where priority ='%s' and rank > %d ", pushQtbl, q->priority, q->rank); sqlUpdate(conn, query); } /* if not deleted, then if new or priority class change, then take last rank */ if (!sameString(delbutton,"delete")) { if ((!sameString(newPriority,q->priority)) || isNew) { q->rank = getNextAvailRank(newPriority); safef(q->priority, sizeof(q->priority), newPriority); } } if (q->priority[0]=='L') { q->rank = 0; } if (sameString(pushbutton,"push requested")) { /* reset pushState in case was prev-> a log already */ safef(q->pushState,sizeof(q->pushState),"Y"); } if (sameString(delbutton,"delete")) { /* delete old record */ safef(query, sizeof(query), "delete from %s where qid ='%s'", pushQtbl, q->qid); sqlUpdate(conn, query); } else { if (sameString(showSizes,"Show Sizes") || sameString(transfer,"Transfer")) { /* mark record as locked */ safef(q->lockUser, sizeof(q->lockUser), qaUser); strftime(q->lockDateTime, sizeof(q->lockDateTime), "%Y-%m-%d %H:%M", loctime); } else { /* unlock record */ safef(q->lockUser, sizeof(q->lockUser), "%s", ""); safef(q->lockDateTime, sizeof(q->lockDateTime), "%s", ""); } if (isNew) { /* save new record */ safef(msg, sizeof(msg), "%%0%dd", (int)sizeof(q->qid)-1); safef(newQid,sizeof(newQid),msg,newqid); safef(q->qid, sizeof(q->qid), newQid); safef(msg, sizeof(msg), "%s", ""); pushQSaveToDbEscaped(conn, q, pushQtbl, updateSize); } else { /* update existing record */ pushQUpdateEscaped(conn, q, pushQtbl, updateSize); } } if (sameString(clonebutton,"clone")) { /* save new clone */ safef(q->pqid,sizeof(q->pqid), q->qid); /* daughter will point to parent */ newqid = getNextAvailQid(); safef(msg, sizeof(msg), "%%0%dd", (int)sizeof(q->qid)-1); safef(newQid,sizeof(newQid),msg,newqid); safef(q->qid, sizeof(q->qid), newQid); safef(msg, sizeof(msg), "%s", ""); if (q->priority[0]=='L') { q->rank = 0; } else { q->rank = getNextAvailRank(q->priority); } safef(q->pushState,sizeof(q->pushState),"N"); /* default to: push not done yet */ pushQSaveToDbEscaped(conn, q, pushQtbl, updateSize); } if (sameString(showSizes,"Show Sizes")) { cgiVarSet("qid", q->qid); /* for new rec */ doShowSizes(); } else if (sameString(transfer,"Transfer")) { cgiVarSet("qid", q->qid); /* for new rec */ doTransfer(); } else if (sameString(submitbutton,"Submit")) { /* if submit button, saved data, now return to readonly view-> */ safef(msg, sizeof(msg), "Data saved->"); cgiVarSet("qid", q->qid); /* for new rec */ doEdit(); } else { doDisplay(); } pushQFree(&q); } void doEdit() /* Handle edit request for a pushQ entry */ { int updateSize = 2456; struct pushQ *q; q = loadPushQ(cgiString("qid")); if (!q) { printf("Queue Id %s not found.", cgiString("qid")); return; } if ( sameString(qaUser,"kuhn") || sameString(qaUser,"kuhn2") || sameString(qaUser,"mary") || sameString(qaUser,"ann") || sameString(qaUser,"antonio") ) /* for users that want to automatically try to lock record immediately */ { if (sameString(action,"edit") || sameString(action,"setSize")) { if (sameString(q->lockUser,"")) /* q->lockUser blank if nobody has lock */ { safef(q->lockUser, sizeof(q->lockUser), qaUser); strftime(q->lockDateTime, sizeof(q->lockDateTime), "%Y-%m-%d %H:%M", loctime); pushQUpdateEscaped(conn, q, pushQtbl, updateSize); } } else /* we are coming back from a post? so return to display automatically */ { doDisplay(); return; /* this is needed? */ } } replacePushQFields(q, FALSE); /* new rec = false */ pushQFree(&q); } void doSetSize() /* save sizeMB */ { struct pushQ *q; char tempSizeMB[10]; int updateSize=2456; q = loadPushQ(cgiString("qid")); if (!q) { printf("Queue Id %s not found.", cgiString("qid")); return; } safef(tempSizeMB,sizeof(tempSizeMB), cgiUsualString("sizeMB","")); if (!sameString(tempSizeMB,"")) { if (sscanf(tempSizeMB,"%u",&q->sizeMB) != 1) { q->sizeMB = 0; } } pushQUpdateEscaped(conn, q, pushQtbl, updateSize); doEdit(); pushQFree(&q); } void doLogin() /* make form for login */ { printf("

Login

\n"); printf("
\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("
\n"); printf("User:\n"); printf("\n"); printf("\n"); printf("
\n"); printf("Password:\n"); printf("\n"); printf("
\n"); printf("
\n"); printf(" \n"); printf("\n"); printf("\n"); printf("
\n"); if (sameString(utsName.nodename,"hgwdev")) { printf("

Machine: %s THIS IS NOT THE REAL PUSHQ- GO TO " "HGWBETA

\n",utsName.nodename); } printf("
\n"); printf("
\n"); printf("%s
\n",msg); } void doLogoutMsg() /* let user know logged-out ok */ { printf("

Logged Out

\n"); printf("
\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("
\n"); printf("\n"); printf("
\n"); printf("
\n"); } void doCookieReset() /* reset cookie, will cause new login next time */ { htmlSetCookie("qapushq", "", NULL, NULL, ".cse.ucsc.edu", FALSE); htmShell(TITLE, doLogoutMsg, NULL); } bool readAUser(struct users *u, bool optional) /* read data for my user */ { char query[256]; char **row; struct sqlResult *sr; safef(query, sizeof(query), "select * from users where user = '%s'",u->user); sr = sqlGetResult(conn, query); row = sqlNextRow(sr); if (row == NULL) { if (optional) { sqlFreeResult(&sr); return FALSE; } else { errAbort("%s not found.",u->user); } } else { usersStaticLoad(row,u); } sqlFreeResult(&sr); return TRUE; } void readMyUser() /* read data for my user */ { int i = 1; /* because it should start right off with ? */ char tempVar[2048]; char tempVarName[256]; char tempVal[2048]; if ((qaUser == NULL) || (sameString(qaUser,""))) { return; } safef(myUser.user,sizeof(myUser.user),qaUser); readAUser(&myUser, FALSE); while(parseList(myUser.contents,'?',i,tempVar,sizeof(tempVar))) { parseList(tempVar,'=',0,tempVarName,sizeof(tempVarName)); parseList(tempVar,'=',1,tempVal,sizeof(tempVal)); if (sameString(tempVarName,"showColumns")) { showColumns = cloneString(tempVal); } if (sameString(tempVarName,"org")) { safef(pushQtbl,sizeof(pushQtbl),tempVal); } if (sameString(tempVarName,"month")) { safef(month,sizeof(month),tempVal); } if (sameString(tempVarName,"oldRandState")) { oldRandState = cloneString(tempVal); } i++; } } void saveMyUser(); /* forward declaration */ void doPostLogin() /* process Login post */ { char *tbl = "users"; char query[256]; struct users u; char *userPassword = NULL; bool loginOK = FALSE; char *meta = "" "" "" "Meta Redirect Code" "" "" ""; userPassword = cgiString("password"); ZeroVar(&u); u.next = NULL; safef(u.user, sizeof(u.user), cgiString("user")); conn = sqlConnectRemote(host, user, password, database); /* do db conn here special for login */ if (!readAUser(&u, TRUE)) { /* unknown user not allowed */ safef(msg,sizeof(msg),"Invalid user or password."); } else { if (strlen(u.password)==0) { /* if pwd in db is blank, use this as their new password and encrypt it and save in db. */ if (strlen(userPassword) < 6) { /* bad pwd */ safef(msg,sizeof(msg),"Invalid password. Password must be at least 6 characters long."); } else { encryptNewPWD(userPassword, u.password, sizeof(u.password)); safef(query, sizeof(query), "update %s set password = '%s' where user = '%s' ", tbl, u.password, u.user); sqlUpdate(conn, query); loginOK = TRUE; } } else { /* verify password matches db */ if (checkPWD(userPassword, u.password)) { /* good pwd, save user in cookie */ loginOK = TRUE; } else { /* bad pwd */ safef(msg,sizeof(msg),"Invalid user or password."); } } } if (loginOK) { /* try to make same cookie work with both hgwdev and hgwbeta to obviate need for double-login */ /* note: for permanent cookie, set NULL to expire in format "Wdy, DD-Mon-YYYY HH:MM:SS GMT" (must be GMT) */ htmlSetCookie("qapushq", u.user, NULL, NULL, ".cse.ucsc.edu", FALSE); qaUser=u.user; oldRandState=""; showColumns=cloneString(defaultColumns); readMyUser(); oldRandState=""; saveMyUser(); safef(msg, sizeof(msg),"Login successful."); htmShellWithHead(TITLE, meta, doMsg ,NULL); /* this is now the only redirect */ } else { htmShell(TITLE, doLogin, NULL); } sqlDisconnect(&conn); } void saveMyUser() /* read data for my user */ { char *tbl = "users"; struct dyString * query = NULL; query = newDyString(2048); if ((qaUser == NULL) || (sameString(qaUser,""))) { return; } dyStringPrintf(query, "update %s set contents = '?showColumns=%s?org=%s?month=%s?oldRandState=%s' where user = '%s'", tbl, showColumns, pushQtbl, month, oldRandState, myUser.user); sqlUpdate(conn, query->string); freeDyString(&query); } void XdoPromoteColumn(int change) /* Promote the column * 1 = promote, 0 = hide, -1 = demote */ { char target[256] = ""; int i = 0; char tempBefore[256] = ""; char tempVal [256] = ""; char tempAfter [256] = ""; char tempSwap [256] = ""; struct dyString * s = NULL; s = newDyString(2048); /* need room */ safef(target, sizeof(target), cgiString("col")); while(TRUE) { parseList(showColumns,',',i,tempAfter,sizeof(tempAfter)); if ((tempBefore[0]==0) && (tempVal[0]==0) && (tempAfter[0]==0)) { break; } if (sameString(target,tempVal)) { if (change==1) { /* swap places with Before */ safef(tempSwap , sizeof(tempSwap ), tempBefore); safef(tempBefore, sizeof(tempBefore), tempVal ); safef(tempVal , sizeof(tempVal ), tempSwap ); } if (change==0) { /* remove */ tempVal[0]=0; /* set to empty string, output will be skipped */ } if (change==-1) { /* swap places with After */ safef(tempSwap , sizeof(tempSwap ), tempAfter ); safef(tempAfter , sizeof(tempAfter ), tempVal ); safef(tempVal , sizeof(tempVal ), tempSwap ); } change = 99; /* just suppress any more changes */ } if (!sameString(tempBefore,"")) { dyStringPrintf(s, "%s,", tempBefore); } /* roll 'em! */ safef(tempBefore, sizeof(tempBefore), tempVal ); safef(tempVal , sizeof(tempVal) , tempAfter); i++; } showColumns = cloneString(s->string); freeDyString(&s); showColumns[strlen(showColumns)-1]=0; /* chop off trailing comma */ doDisplay(); } void doPromoteColumn() { XdoPromoteColumn(1); } void doHideColumn() { XdoPromoteColumn(0); } void doDemoteColumn() { XdoPromoteColumn(-1); } void doShowAllColumns() /* Display hidden columns available for resurrection */ { int c = 0; char templist[512]; char tempe[64]; printf("

Show Hidden Columns

\n"); printf("
\n"); printf("RETURN
", newRandState); printf("
\n"); printf("Click on any column below to un-hide it.
\n"); printf("
\n"); safef(templist,sizeof(templist),",%s,",showColumns); /* add sentinel comma values to the ends of the col list */ for (c=0; c%s

", colName[c], newRandState, colName[c]); } } printf("
\n"); printf("RETURN
", newRandState); } void doShowColumn() /* Make column visible again */ { struct dyString * s = NULL; char *colName = NULL; char templist[512]; char tempe[64]; s = newDyString(2048); /* need room */ colName = cgiString("colName"); mapFieldToEnum(colName,TRUE); /* this will make sure it exists or errAbort */ safef(templist,sizeof(templist),",%s,",showColumns); /* add sentinel comma values to the ends of the col list */ safef(tempe,sizeof(tempe),",%s,",colName); /* add sentinel comma values to the ends of the col element */ if (strstr(templist,tempe)==NULL) /* make sure not already in list */ { dyStringAppend(s, showColumns); dyStringPrintf(s, ",%s", colName); showColumns = cloneString(s->string); } freeDyString(&s); doDisplay(); } void doShowDefaultColumns() /* Show Default Columns in default order */ { showColumns = cloneString(defaultColumns); doDisplay(); } void doShowMonths() /* This gives the user a choice of months to filter on */ { struct sqlResult *sr; char **row; char query[256]; printf("

Logs for Month

\n"); printf("
\n"); printf("Current
\n", newRandState); printf("
\n"); safef(query, sizeof(query), "select distinct substring(qadate,1,7) from %s where priority='L' order by qadate desc",pushQtbl); sr = sqlGetResult(conn, query); while ((row = sqlNextRow(sr)) != NULL) { printf("%s
\n",row[0],newRandState,row[0]); } sqlFreeResult(&sr); printf("
\n"); printf("RETURN
", newRandState); } void getIndexes(struct sqlConnection *conn, char *tbl, char *s, int ssize) /* Get indexes with show index on table command. Return -1 if err. * Will match multiple if "%" used in tbl */ { char query[256]; char **row; struct sqlResult *sr; char *fld = NULL; int f = 0, i = 0, n = 0, c = 0; char lastKeyName[256]=""; safef(query, sizeof(query), "show index from %s",tbl); sr = sqlGetResult(conn, query); f = 0; i = 0; n = 0; if (ssize > 0) s[0]=0; while ((fld = sqlFieldName(sr)) != NULL) { if (sameString(fld,"Key_name")) { n = f; } if (sameString(fld,"Column_name")) { i = f; } f++; } while ((row = sqlNextRow(sr)) != NULL) { c++; if (sameString(row[n],lastKeyName)) { strcat(s,"+"); strcat(s,row[i]); } else { if (c > 1) { strcat(s,", "); } strcat(s, row[i]); safef(lastKeyName,sizeof(lastKeyName),row[n]); } } sqlFreeResult(&sr); sqlDisconnect(&conn); } void mySprintWithCommas(char *s, int slength, long long size) /* the one in obscure.c was overflowing, so here's mine */ { char *temp=NULL; char sep[2]=""; s[0]=0; temp = needMem(slength); while (size >= 1000) { safef(temp,slength,s); safef(s,slength,"%03d%s%s",(int)(size%1000),sep,temp); size/=1000; safef(sep,sizeof(sep),","); } if (size > 0) { safef(temp,slength,s); safef(s,slength,"%3d%s%s",(int)size,sep,temp); } else { safef(s,slength,"0"); /* special case zero*/ } freez(&temp); } long long pq_getTableSize(char *rhost, char *db, char *tbl, int *errCount) /* added extension pq_ to supress name conflict in hdb.c */ /* Get table size via show table status command. Return -1 if err. * Will match multiple if "%" used in tbl */ { char query[256]; char **row; struct sqlResult *sr; char *fld = NULL; int f = 0, d = 0, i = 0, n = 0, c = 0; unsigned long size = 0; long long totalsize = 0; char nicenumber[256]=""; char indexlist[256]=""; char *host = NULL; char *user = NULL; char *password = NULL; struct sqlConnection *conn = NULL; host = cfgOption("db.host" ); user = cfgOption("db.user" ); password = cfgOption("db.password"); if ((sameString(utsName.nodename,"hgwbeta")) && (sameString(rhost,"hgwdev"))) { host = "hgwdev"; user = cfgOption("db.user" ); password = cfgOption("db.password"); } if ((sameString(utsName.nodename,"hgwdev")) && (sameString(rhost,"hgwbeta"))) { // inaccurate but doesn't matter since we only use it to test qaPushQ cgi on dev. host = cfgOption("central.host" ); user = cfgOption("central.user" ); password = cfgOption("central.password"); } conn = sqlConnectRemote(host, user, password, db); safef(query, sizeof(query), "show table status like '%s'",tbl); sr = sqlGetResult(conn, query); f = 0; d = 0; i = 0; n = 0; while ((fld = sqlFieldName(sr)) != NULL) { if (sameString(fld,"Name")) { n = f; } if (sameString(fld,"Data_length")) { d = f; } if (sameString(fld,"Index_length")) { i = f; } f++; } while ((row = sqlNextRow(sr)) != NULL) { c++; printf(""); printf("%s",row[n]); sscanf(row[d],"%lu",&size); totalsize+=size; mySprintWithCommas(nicenumber, sizeof(nicenumber), size); printf("%s",nicenumber); sscanf(row[i],"%lu",&size); totalsize+=size; mySprintWithCommas(nicenumber, sizeof(nicenumber), size); printf("%s",nicenumber); getIndexes( sqlConnectRemote(host, user, password, db), row[n], indexlist, sizeof(indexlist)); printf("%s",indexlist); printf("\n"); } sqlFreeResult(&sr); if (c == 0) { printf("%s%s\n",tbl,"error fetching"); ++(*errCount); } sqlDisconnect(&conn); return totalsize; } void cutParens(char *s) /* internally modify string to remove parens and anything they contain. nested ok, but must be balanced. */ { int i=0,j=0,l=0,c=0; l=strlen(s); for(i=0;i<=l;i++) { switch (s[i]) { case '(': c++; break; case ')': c--; break; case 0: c = 0; default: if (c==0) { s[j++]=s[i]; } } } } void whiteSpace(char *s) /* internally modify string to convert whitespace to space chars. */ { char *ss = NULL; int i=0,ii=0,l=0; char c=' '; l=strlen(s); ss =needMem(l+1); for(i=0;i<=l;i++) { c = s[i]; switch (c) { case '\t' : case '\n' : case '\r' : case '\f' : c = ' '; default: ss[ii++]=c; } } safef(s, l+1, "%s", ss); } void doShowSizes() /* show the sizes of all the track tables, cgis, and general files in separate window target= _blank */ { char tbl[BLSIZE] = ""; char db[1024] = ""; off_t size = 0; off_t totalsize = 0; unsigned long sizeMB = 0; int errCount = 0; off_t totalTable = 0; off_t totalGbdb = 0; off_t totalGoldenPath = 0; int tableCount = 0; int gbdbCount = 0; int goldenCount = 0; int i = 0, ii = 0, iii = 0; int j = 0, jj = 0, jjj = 0; int g = 0, gg = 0, ggg = 0; char nicenumber[1024]=""; struct pushQ *q; char newQid[sizeof(q->qid)] = ""; char dbsComma[1024]; char dbsSpace[1024]; char dbsVal[1024]; char d; char tempComma[BLSIZE]; char tempSpace[BLSIZE]; char tempVal[BLSIZE]; char c; char gComma[BLSIZE]; char gSpace[BLSIZE]; char gVal[BLSIZE]; char gc; char cgiPath[1024]; char pathName[1024]; char filePath[1024]; char fileName[1024]; char *found=NULL; struct fileInfo *fi = NULL; char *crossUrl = ""; safef(newQid, sizeof(newQid), cgiString("qid")); printf("

Show File Sizes

\n"); q = mustLoadPushQ(newQid); if (crossPost) // support showSizes across machines { crossUrl = sameString(utsName.nodename, "hgwdev") ? "http://hgwbeta.cse.ucsc.edu" : "http://hgwdev.cse.ucsc.edu"; } printf("HELP \n", crossUrl,q->qid,newRandState); printf("RETURN \n",crossUrl,newQid,newRandState); printf("
\n"); printf("Location: %s
\n",q->currLoc); printf("Database: %s
\n",q->dbs ); /* deemed too verbose: */ //printf(" Tables: %s
\n",q->tbls ); //printf(" CGIs: %s
\n",q->cgis ); //printf(" Files: %s
\n",q->files ); cutParens(q->dbs); cutParens(q->tbls); cutParens(q->cgis); cutParens(q->files); whiteSpace(q->dbs); whiteSpace(q->tbls); whiteSpace(q->cgis); whiteSpace(q->files); q->tbls = replaceChars(q->tbls,"chrN_","chr*_"); q->tbls = replaceChars(q->tbls,"\\","\\\\"); q->tbls = replaceChars(q->tbls,"%","\\%"); q->tbls = replaceChars(q->tbls,"_","\\_"); for(j=0;parseList(q->dbs, ',' ,j,dbsComma,sizeof(dbsComma));j++) { if (dbsComma[0]==0) { continue; } for(jj=0;parseList(dbsComma, ' ' ,jj,dbsSpace,sizeof(dbsSpace));jj++) { if (dbsSpace[0]==0) { continue; } dbsVal[0]=0; for (jjj=0;jjj<=strlen(dbsSpace);jjj++) { d = dbsSpace[jjj]; if ( ((d>='A')&&(d<='Z')) || ((d>='a')&&(d<='z')) || ((d>='0')&&(d<='9')) ) { dbsVal[jjj]=d; } else { dbsVal[jjj]=0; break; } } if (dbsVal[0]!=0) { safef(db,sizeof(db),"%s",dbsVal); printf("
\n"); printf("

%s on %s:

\n",db,q->currLoc); printf(""); printf("" "" "" "" ); /* we parsed the db multiples, now parse the tbl mutiples */ for(i=0;parseList(q->tbls, ',' ,i,tempComma,sizeof(tempComma));i++) { if (tempComma[0]==0) { continue; } for(ii=0;parseList(tempComma, ' ' ,ii,tempSpace,sizeof(tempSpace));ii++) { if (tempSpace[0]==0) { continue; } tempVal[0]=0; for (iii=0;iii<=strlen(tempSpace);iii++) { c = tempSpace[iii]; if (c=='*') c = '%'; if ( ((c>='A')&&(c<='Z')) || ((c>='a')&&(c<='z')) || ((c>='0')&&(c<='9')) || (c=='_') || (c=='%') || (c=='\\') ) { tempVal[iii]=c; } else { tempVal[iii]=0; break; } } if (tempVal[0]!=0) { safef(tbl,sizeof(tbl),"%s",tempVal); long long tableSize = pq_getTableSize(q->currLoc,db,tbl,&errCount); totalsize += tableSize; totalTable += tableSize; ++tableCount; } } } printf("
Tabledata sizeindex sizeindex keys
"); } } } if (!sameString(q->cgis,"")) { printf("
\n"); printf("

CGIs on %s:

\n",utsName.nodename); printf(""); printf(""); for(g=0;parseList(q->cgis, ',' ,g,gComma,sizeof(gComma));g++) { if (gComma[0]==0) { continue; } for(gg=0;parseList(gComma, ' ' ,gg,gSpace,sizeof(gSpace));gg++) { if (gSpace[0]==0) { continue; } gVal[0]=0; for (ggg=0;ggg<=strlen(gSpace);ggg++) { gc = gSpace[ggg]; if ( ((gc>='A')&&(gc<='Z')) || ((gc>='a')&&(gc<='z')) || ((gc>='0')&&(gc<='9')) || (gc=='.') ) { gVal[ggg]=gc; } else { gVal[ggg]=0; break; } } if (gVal[0]!=0) { safef(cgiPath,sizeof(cgiPath),"%s%s","./",gVal); size=fileSize(cgiPath); if (size == -1) { printf("\n",gVal); ++errCount; } else { totalsize+=size; sprintLongWithCommas(nicenumber, size); printf("\n",gVal,nicenumber); } } } } printf("
cgi# bytes
%snot found
%s%s
"); } if (!sameString(q->files,"")) { printf("
\n"); printf("

Files on %s:

\n",utsName.nodename); printf(""); printf(""); for(g=0;parseList(q->files, ',' ,g,gComma,sizeof(gComma));g++) { if (gComma[0]==0) { continue; } for(gg=0;parseList(gComma, ' ' ,gg,gSpace,sizeof(gSpace));gg++) { if (gSpace[0]==0) { continue; } gVal[0]=0; for (ggg=0;ggg<=strlen(gSpace);ggg++) { gc = gSpace[ggg]; if ( ((gc>='A')&&(gc<='Z')) || ((gc>='a')&&(gc<='z')) || ((gc>='0')&&(gc<='9')) || (gc=='.') || (gc=='/') || (gc=='-') || (gc=='_') || (gc=='*') ) { gVal[ggg]=gc; } else { gVal[ggg]=0; break; } } if (gVal[0]!=0) { if (strrchr(gVal, '*') == NULL) { /* no wildcards in filename, do it the normal way */ safef(pathName,sizeof(pathName),"%s",gVal); size=fileSize(pathName); if (size == -1) { printf("\n",gVal); ++errCount; } else { totalsize+=size; sprintLongWithCommas(nicenumber, size); printf("\n",gVal,nicenumber); if (startsWith("/gbdb/", pathName)) { totalGbdb+=size; ++gbdbCount; } if (stringIn("/goldenPath/", pathName)) { totalGoldenPath+=size; ++goldenCount; } } } else { /* wildcards found in name, use listDirX */ printf("\n",gVal); found = strrchr(gVal, '/'); if (found == NULL) { filePath[0]=0; safef(fileName,sizeof(fileName),"%s",gVal); } else { *found = 0; safef(filePath,sizeof(filePath),"%s",gVal); found++; safef(fileName,sizeof(fileName),"%s",found); } for (fi = listDirXExt(filePath,fileName,FALSE,TRUE);fi!=NULL;fi=fi->next) { if (fi->statErrno > 0) // usually due to bad symlink { char *errStr = htmlEncode(strerror(fi->statErrno)); printf("\n" , fi->name , errStr); freeMem(errStr); ++errCount; } else if (fi->isDir) { printf("\n",fi->name); ++errCount; } else { totalsize+=fi->size; if (startsWith("/gbdb/", filePath)) { ++gbdbCount; totalGbdb+=fi->size; } if (stringIn("/goldenPath/", filePath)) { ++goldenCount; totalGoldenPath+=fi->size; } sprintLongWithCommas(nicenumber, fi->size); printf("\n",fi->name,nicenumber); } } printf("\n"); /* spacer */ } } } } printf("
file# bytes
%snot found
%s%s
expansion for %s
%s" "stat() failed: %s
error: %s is a directory
%s%s
 
"); } if (totalTable > 0) { printf("
\n"); mySprintWithCommas(nicenumber, sizeof(nicenumber), totalTable); printf(" Total size of tables: %s ",nicenumber); sprintWithGreekByte(nicenumber, sizeof(nicenumber), totalTable); printf("  ( %s ) ",nicenumber); mySprintWithCommas(nicenumber, sizeof(nicenumber), tableCount); printf("  ( %s tables )
\n", nicenumber); } if (totalGbdb > 0) { printf("
\n"); mySprintWithCommas(nicenumber, sizeof(nicenumber), totalGbdb); printf(" Total size of /gbdb/ files: %s ",nicenumber); sprintWithGreekByte(nicenumber, sizeof(nicenumber), totalGbdb); printf("  ( %s ) ",nicenumber); mySprintWithCommas(nicenumber, sizeof(nicenumber), gbdbCount); printf("  ( %s gbdb files )
\n", nicenumber); } if (totalGoldenPath > 0) { printf("
\n"); mySprintWithCommas(nicenumber, sizeof(nicenumber), totalGoldenPath); printf(" Total size of .../goldenPath/ files: %s ",nicenumber); sprintWithGreekByte(nicenumber, sizeof(nicenumber), totalGoldenPath); printf("  ( %s ) ",nicenumber); mySprintWithCommas(nicenumber, sizeof(nicenumber), goldenCount); printf("  ( %s goldenPath files )
\n", nicenumber); } printf("
\n"); mySprintWithCommas(nicenumber, sizeof(nicenumber), totalsize); printf(" Total size of all: %s ",nicenumber); sprintWithGreekByte(nicenumber, sizeof(nicenumber), totalsize); printf("  ( %s )
\n",nicenumber); printf("
\n"); sizeMB = (((totalsize * 1.0) / (1024 * 1024)) + 0.5); if ((sizeMB == 0) && (totalsize > 0)) { sizeMB = 1; } sprintLongWithCommas(nicenumber, sizeMB ); printf("

Total: %s MB",nicenumber); if (errCount) { printf("   Errors: %d",errCount); } printf("

\n"); printf("
\n"); printf("" "Set Size as %s MB
\n",crossUrl,newQid,sizeMB,newRandState,nicenumber); printf("
\n"); printf("RETURN
\n",crossUrl,newQid,newRandState); pushQFree(&q); } void listQueues(char *action, boolean isTransfer); /* forward decl */ void doTransfer() /* Present choice of queues to which the selected and locked record may be transferred */ { struct pushQ *q; char newQid[sizeof(q->qid)] = ""; char tempUrl[256]; ZeroVar(&q); safef(newQid, sizeof(newQid), cgiString("qid")); printf("

Transfer Queue Entry %s:%s to Another Queue

\n", pushQtbl, newQid); q=mustLoadPushQ(newQid); printf("RETURN \n",newQid,newRandState); printf("
\n"); printf("
\n"); safef(tempUrl, sizeof(tempUrl), "action=transferTo&qid=%s&toOrg", newQid); listQueues(tempUrl, TRUE); printf("RETURN
\n",newQid,newRandState); pushQFree(&q); } void doTransferTo() /* Execute transfer of qid from current pushQtbl to named target Q table */ { struct pushQ *q; int updateSize = 2456; /* almost anything works here */ char *toOrg = cgiString("toOrg"); /* required cgi var */ char *origQid = NULL; int newqid = 0; char newQid [sizeof(q->qid)] = ""; char *savePushQtbl = cloneString(pushQtbl); char query[256]; origQid = cloneString(cgiString("qid")); /* required cgi var */ /* get the data from the record */ q = mustLoadPushQ(origQid); /* first close the hole where it was */ safef(query, sizeof(query), "update %s set rank = rank - 1 where priority ='%s' and rank > %d ", pushQtbl, q->priority, q->rank); sqlUpdate(conn, query); /* delete old record */ safef(query, sizeof(query), "delete from %s where qid ='%s'", pushQtbl, origQid); sqlUpdate(conn, query); /* temporarily set pushQtbl to target */ safef(pushQtbl, sizeof(pushQtbl), "%s",toOrg); /* unlock record - don't want it to keep the lock status after xfer */ safef(q->lockUser, sizeof(q->lockUser), "%s",""); safef(q->lockDateTime, sizeof(q->lockDateTime), "%s",""); /* get the maxQid from the target Q tbl */ newqid = getNextAvailQid(); safef(msg, sizeof(msg), "%%0%dd", (int)sizeof(q->qid)-1); safef(newQid,sizeof(newQid),msg,newqid); safef(q->qid, sizeof(q->qid), newQid); safef(msg, sizeof(msg), "%s", ""); /* get the maxrank from the target Q tbl for given priority */ if (q->priority[0]=='L') { q->rank = 0; } else { q->rank = getNextAvailRank(q->priority); } /* clear parent link since can not be maintained */ safef(q->pqid, sizeof(q->pqid), "%s", ""); /* save record into new target Q */ pushQSaveToDbEscaped(conn, q, pushQtbl, updateSize); /* restore pushQtbl */ safef(pushQtbl, sizeof(pushQtbl), "%s", savePushQtbl); /* set msg to display the new Qid to the user, visible on return */ safef(msg,sizeof(msg),"Transferred %s Qid %s to %s Qid %s.
\n", pushQtbl, origQid, toOrg, q->qid); doDisplay(); freez(&origQid); freez(&savePushQtbl); pushQFree(&q); } void doShowDisplayHelp() /* show the sizes of all the track tables, cgis, and general files in separate window target= _blank */ { printf("

Display Help

\n"); printf("
\n"); printf("NOTE: DO NOT USE BACK-BUTTON OR REFRESH ON YOUR BROWSER.
\n"); printf("
\n"); printf("     NAVIGATION BUTTONS AND LINKS ARE PROVIDED.
\n"); printf("
\n"); printf("ADD - add a new Push Queue record.
\n"); printf("Logout - clears your cookie and logs out.
\n"); printf("All Columns - allows you to bring back hidden columns.
\n"); printf("Default Columns - reset your column preferences to default columns and order.
\n"); printf("Log by Month - view old log records by month
\n"); printf("Gateway - click to select alternate push queues, if any, e.g. new track/org
\n"); printf("HELP - click to see this help.
\n"); printf("Refresh - click to see if others have made changes.
\n"); printf("
\n"); printf("! - click to hide a column you do not wish to see.
\n"); printf("< - click to move the column to the left.
\n"); printf("> - click to move the column to the right.
\n"); printf("
\n"); printf("^ - click to raise the priority of the record higher within the priority-class.
\n"); printf("v - click to lower the priority.
\n"); printf("T - click to raise to top priority.
\n"); printf("B - click to lower to bottom priority.
\n"); printf("
\n"); printf("Queue Id - click to edit or see the details page for the record.
\n"); printf("
\n"); printf("CLOSE
\n"); } void doShowEditHelp() /* show the sizes of all the track tables, cgis, and general files in separate window target= _blank */ { struct pushQ q; ZeroVar(&q); safef(q.qid,sizeof(q.qid),cgiString("qid")); printf("

Details/Edit Help

\n"); printf("
\n"); printf("CANCEL - click to return to main display without saving changes.
\n"); printf("HELP - click to see this help.
\n"); printf("
\n"); printf("Initial submission - displays date automatically generated when push queue record is created.
\n"); printf("Importance - from Redmine.
\n"); printf("Date Opened - date QA (re)opened. (YYYY-MM-DD) Defaults originally to current date to save typing.
\n"); printf("New track? - choose Y if this is a new track (i.e. has never before appeared on beta).
\n"); printf("Track - enter the track name as it will appear in the genome browser (use the shortLabel).
\n"); printf("Release Log- enter the short Label (usually) followed by notes in parentheses if any. This appears in the release log unless empty.
\n"); printf("Databases - enter db name. May be comma-separated list if more than one organism, etc.
\n"); printf("Tables - enter as comma-separated list all tables that apply. They must exist in the database specified. Wildcard * supported. (Put comments in parentheses).
\n"); printf("CGIs - enter names of any new cgis that are applicable. Must be found on hgwbeta.
\n"); printf("Files - enter pathnames of any additional files if needed.
\n"); printf("Size(MB) - enter the size of the total push in megabytes (MB).
\n"); printf("Show Sizes button - click to see a complete list of sizes of all tables and cgis. Tables are relative to Current Location specified.
\n"); printf("Current Location - chooose the current location of the files. Should default to hgwdev at start, after sudo mypush to hgwbeta, change this to hgwbeta.
\n"); printf("Makedoc verified? - choose Y if you have verified the MakeAssembly.doc in kent/src/hg/makeDb.
\n"); printf("Online help - enter status of online help. Verify hgTracksHelp
\n"); printf("Index verified? - choose Y if the index has been verified. Use the ShowSizes button for a quick view.
\n"); printf("All.joiner verified? - choose Y if the all.joiner in /hg/makeDb/schema has been verified.
\n"); printf("Status - enter current status (255 char max). Put long notes in Open Issues or Notes.
\n"); printf("Sponsor - usually the developer.
\n"); printf("Reviewer - usually the QA person handling the push queue for the track.
\n"); printf("External Source or Collaborator - external contact outside our staff that may be involved.
\n"); printf("Open Issues - Record any remaining open issues that are not completely resolved (no size limit here).
\n"); printf("Notes - Any other notes you would like to make (no size limit here).
\n"); printf("
\n"); printf("Submit button - save changes and return to main display.
\n"); printf("delete button - delete this push queue record and return to main display.
\n"); printf("push requested button - press only if you are QA staff and about to submit the push-request. It will try to verify that required entries are present.
\n"); printf("clone button - press if you wish to split the original push queue record into multiple parts. Saves typing, used rarely.
\n"); printf("bounce button - press to bounce from priority A, the QA queue, to B, the developer queue if it needs developer attention.
\n"); printf("transfer button - press to transfer the pushQ entry to another queue.
\n"); printf("lock - press lock to lock the record and edit it. When in edit mode, make your changes and submit. Do not leave the record locked.
\n"); printf("
\n"); printf("CLOSE
\n"); } void doShowSizesHelp() /* show the sizes of all the track tables, cgis, and general files in separate window target= _blank */ { struct pushQ q; ZeroVar(&q); safef(q.qid,sizeof(q.qid),cgiString("qid")); printf("

Show File Sizes Help

\n"); printf("
\n"); printf("Tables: Shows sizes of database data and indexes.
\n"); printf("Expands wildcard * in table names list.
\n"); printf("Shows total index size, and the key expression of each index.
\n"); printf("Location of tables is relative to the Current Location setting in the record.
\n"); printf("
\n"); printf("CGIs: shows files specified. Currently limited to checking localhost (hgwbeta in this case).
\n"); printf("
\n"); printf("Total size of all: total size of all files found in bytes.
\n"); printf("Total: size in megabytes(MB) which is what should be entered into the size(MB) field of the push queue record.
\n"); printf("
\n"); printf("RETURN - click to return to the details/edit page.
\n"); printf("Set Size As - click to set size to that found, and return to the details/edit page. Saves typing. Be sure to press submit to save changes.
\n"); printf("
\n"); printf("
\n"); printf("CLOSE
\n"); } void checkConn2() /* get 2nd conn, if not already done */ { if (!conn2) conn2 = sqlConnectRemote(host, user, password, database); } boolean verifyTableIsQueue(char *table) /* Return TRUE if table is a push Q */ { boolean result = TRUE; char query[256]; char *field = NULL; safef(query, sizeof(query), "desc %s",table); checkConn2(); field = sqlQuickString(conn2, query); result = sameString(field,"qid"); freez(&field); return result; } void listQueues(char *action, boolean isTransfer) /* list the available queues other than self */ { struct sqlResult *sr; char **row; char query[256]; char *monthChange = isTransfer ? "" : "&month=current"; if (!(isTransfer && sameString(pushQtbl,"pushQ"))) { char *extra = (sameString(pushQtbl,"pushQ") ? " (you are here)" : ""); printf("Main Push Queue%s
\n",action,"pushQ",monthChange,newRandState,extra); printf("
\n"); } safef(query, sizeof(query), "show tables"); sr = sqlGetResult(conn, query); while ((row = sqlNextRow(sr)) != NULL) { if (!(isTransfer && sameString(row[0],pushQtbl)) && !sameString(row[0],"pushQ") && !sameString(row[0],"users") && !sameString(row[0],"gbjunk")) { if (verifyTableIsQueue(row[0])) { char *displayQ = row[0]; if (sameString(displayQ,"pushQ")) displayQ = "Main Push Queue"; char *extra = (sameString(row[0],pushQtbl) ? " (you are here)" : ""); printf("%s%s
\n",action,row[0],monthChange,newRandState,displayQ,extra); } } } sqlFreeResult(&sr); printf("
\n"); } void doShowGateway() /* This gives the user a choice of queues to use */ { printf("

Gateway - Choose Queue

\n"); printf("
\n"); listQueues("org", FALSE); printf("RETURN
\n",newRandState); } void doUnlock() /* currently a backdoor for logged-in users to unlock a record */ { struct pushQ *q; int updateSize = 2456; /* almost anything works here */ q = mustLoadPushQ(cgiString("qid")); /* required cgi var */ /* unlock record */ safef(q->lockUser, sizeof(q->lockUser), "%s",""); safef(q->lockDateTime, sizeof(q->lockDateTime), "%s",""); /* update existing record */ pushQUpdateEscaped(conn, q, pushQtbl, updateSize); pushQFree(&q); doDisplay(); } /* ======================================================== */ void doDrawReleaseLog(boolean isEncode) /* Test - draw the release log using log data in pushQ */ { char *centraldb = NULL; char *chost = NULL; char *cuser = NULL; char *cpassword = NULL; struct sqlConnection *betaconn = NULL; struct dbDb *ki=NULL, *kiList=NULL, *dbDbTemp=NULL; struct sqlResult *sr; char **row; char query[256]; char tempName[256]; char now[256]; int m=0,d=0; int topCount=0; char *encodeClause = ""; if (isEncode) encodeClause = " and releaseLog like '%ENCODE%'"; ZeroVar(&dbDbTemp); chost = cfgOption("rrcentral.host" ); cuser = cfgOption("rrcentral.user" ); cpassword = cfgOption("rrcentral.password"); centraldb = cfgOption("rrcentral.db"); webStart(NULL, NULL, "Track and Table Releases"); // only allowed one connection at a time? sqlDisconnect(&conn); betaconn = sqlConnectRemote(chost, cuser, cpassword, centraldb); printf(" This page contains track and table release information for the following genome assemblies:
\n"); safef(query,sizeof(query), "select * from dbDb " "where active=1 " "order by orderKey, name desc"); sr = sqlGetResult(betaconn, query); while ((row = sqlNextRow(sr)) != NULL) { ki = dbDbLoad(row); slAddHead(&kiList, ki); } sqlFreeResult(&sr); slReverse(&kiList); sqlDisconnect(&betaconn); // are we really only allowed one remoteconn at a time? conn = sqlConnectRemote(host, user, password, database); /* filter the db list to make sure we actually have data */ struct dbDb *newList=NULL, *kiNext; for (ki = kiList; ki != NULL; ki = kiNext) { kiNext = ki->next; safef(query,sizeof(query), "select count(*) from pushQ " "where priority='L' and releaseLog != '' and (" "dbs like '%s' or " "dbs like '%s %%' or " "dbs like '%% %s' or " "dbs like '%% %s %%'" ") %s" "order by qadate desc, qid desc", ki->name, ki->name, ki->name, ki->name, encodeClause ); if (sqlQuickNum(conn, query) > 0) { slAddHead(&newList, ki); } } slReverse(&newList); kiList = newList; /* 10 Latest Changes */ printf("
    \n"); printf("
  • 10 Latest Changes (all assemblies)
  • "); /* regular log index #links */ for (ki = kiList; ki != NULL; ki = ki->next) { safef(tempName,sizeof(tempName),ki->organism); if (!sameString(ki->organism, ki->genome)) { safef(tempName,sizeof(tempName),"%s",ki->genome); } printf("
  • %s %s (%s)
  • \n", ki->name,tempName,ki->description,ki->name); } printf("
\n"); printf("

\n"); printf(" For more information about the tracks and tables listed on this page, refer to the " "User's Guide.

\n"); strftime (now, sizeof(now), "%02d %b %Y", loctime); /* default to today's date */ printf("Last updated %s. Inquiries and feedback welcome.\n",now); /* 10 LATEST CHANGES */ webNewSection(" 10 Latest Changes (all assemblies)"); printf("\n" "\n" "\n" "\n" "\n" "\n" ); safef(query,sizeof(query), "select releaseLog, dbs, qadate, releaseLogUrl from pushQ " "where priority='L' and releaseLog != '' and dbs != '' %s" "order by qadate desc, qid desc ", encodeClause ); sr = sqlGetResult(conn, query); while ((row = sqlNextRow(sr)) != NULL) { sscanf(cloneStringZ(&row[2][5],2),"%d",&m); sscanf(cloneStringZ(&row[2][8],2),"%d",&d); { /* parse dblist and make sure it's kosher and active=1 good */ char* dbs = cloneString(row[1]); char dbsComma[1024]; char dbsSpace[1024]; struct dyString* dbList = newDyString(1024); int j = 0, jj = 0; char* sep = ""; boolean found = FALSE; cutParens(dbs); whiteSpace(dbs); for(j=0;parseList(dbs, ',' ,j,dbsComma,sizeof(dbsComma));j++) { if (dbsComma[0]==0) { continue; } for(jj=0;parseList(dbsComma, ' ' ,jj,dbsSpace,sizeof(dbsSpace));jj++) { if (dbsSpace[0]==0) { continue; } for (ki = kiList; ki != NULL; ki = ki->next) { if (sameWord(ki->name,dbsSpace)) { found = TRUE; dyStringPrintf(dbList,"%s%s",sep,dbsSpace); sep=","; } } } } if (found) { topCount++; printf("\n"); printf("\n" "\n" "\n", row[1], d, numberToMonth[m-1], cloneStringZ(row[2],4) ); } freez(&dbs); freeDyString(&dbList); if (topCount>=10) break; } } sqlFreeResult(&sr); printf("
Track/Table NameAssemblyRelease Date
\n"); if (sameOk(row[3], "")) { printf("%s", row[0]); } else { printf("%s", row[3], row[0]); } printf("%s%02d %s %s
\n"); /* REGULAR LOG */ for (ki = kiList; ki != NULL; ki = ki->next) { safef(tempName,sizeof(tempName),ki->organism); if (!sameString(ki->organism, ki->genome)) { safef(tempName,sizeof(tempName),"%s",ki->genome); } webNewSection("%s %s (%s, %s)", ki->name, tempName, ki->description, ki->name, ki->sourceName); printf("\n" "\n" " \n"); safef(query,sizeof(query), "select releaseLog, qadate, releaseLogUrl from pushQ " "where priority='L' and releaseLog != '' and (" "dbs like '%s' or " "dbs like '%s %%' or " "dbs like '%% %s' or " "dbs like '%% %s %%'" ") %s" "order by qadate desc, qid desc", ki->name, ki->name, ki->name, ki->name, encodeClause ); //printf("query=%s\n",query); sr = sqlGetResult(conn, query); while ((row = sqlNextRow(sr)) != NULL) { sscanf(cloneStringZ(&row[1][5],2),"%d",&m); sscanf(cloneStringZ(&row[1][8],2),"%d",&d); printf("\n"); printf( "\n" "\n", d, numberToMonth[m-1], cloneStringZ(row[1],4) ); } sqlFreeResult(&sr); printf("
Track/Table NameRelease Date\n" "
\n"); if (sameOk(row[2], "")) { printf("%s", row[0]); } else { printf("%s", row[2], row[0]); } printf("%02d %s %s
\n"); } dbDbFreeList(&kiList); webEnd(); } void doReleaseLogPush() /* fetch and write releaseLog and display cut-and-pastable push-request */ { //char *rlPath = "/goldenPath/releaseLogNew.html"; //char *apache = "/usr/local/apache/htdocs"; char *rlPath = "/trash/releaseLogNew.html"; char *apache = "/usr/local/apache"; char url[256] = ""; struct htmlPage *page = NULL; char filePath[256] = ""; FILE *f=NULL; safef(url, sizeof(url), "http://%s/cgi-bin/qaPushQ?action=releaseLog",utsName.nodename); page = htmlPageGet(url); if (page->status->status == 200) { safef(filePath,sizeof(filePath),"%s%s",apache,rlPath); f=mustOpen(filePath, "w"); mustWrite(f, page->htmlText, strlen(page->htmlText)); carefulClose(&f); printf("
\n"); printf("Updated release log html %s
\n",rlPath); printf("
\n"); printf("push-request:
\n"); printf("
\n"); printf("Please push from beta to RR,MGC:
\n"); printf("   %s
\n",filePath); printf("
\n"); printf("Thanks!
\n"); printf("
\n"); printf("
\n"); printf("See Release Log
\n",rlPath); } else { printf("Error reading %s: %d
\n",rlPath,page->status->status); } printf("
\n"); printf("CLOSE
\n"); htmlPageFree(&page); } /* ======================================================== */ /* ------------------------------------------------------- */ void doMiddle() /* dispatch events */ { char *org = NULL; /* changes pushQtbl */ char *newmonth = NULL; /* changes month */ char *temp = NULL; char *reqRandState = NULL; /* debug * safef(msg,sizeof(msg),"db='%s', host='%s', user='%s', password='%s'
\n",database,host,user,password); htmShell("Push Queue debug", doMsg, NULL); exit(0); */ if (crossPost) // support showSizes across machines { //host = sameString(utsName.nodename, "hgwdev") ? "hgwbeta.cse.ucsc.edu" : "hgwdev.cse.ucsc.edu"; host = cfgOption("pq.crossHost"); } newRandState = randDigits(20); conn = sqlConnectRemote(host, user, password, database); setLock(); /* default columns */ showColumns = cloneString(defaultColumns); readMyUser(); org = cgiUsualString("org",""); /* get org, defaults to display of main push queue */ if (!sameString(org,"")) { safef(pushQtbl,sizeof(pushQtbl),org); } if (!sqlTableExists(conn, pushQtbl)) /* if pushQtbl no longer exists, switch to main "pushQ" and set action to "display" */ { safef(pushQtbl,sizeof(pushQtbl),"pushQ"); action=cloneString("display"); /* do not need to free action because it just points to a cgi-var hash element */ } newmonth = cgiUsualString("month",""); /* get month, if =current then resets to normal */ if (!sameString(newmonth,"")) { if (sameString(newmonth,"current")) { safef(month, sizeof(month), "%s", ""); } else { temp = needMem(strlen(newmonth)+1+3); safef(temp, strlen(newmonth)+1+3, "%s-01",newmonth); if (isDateValid(temp)) { safef(month,sizeof(month),newmonth); } } } if (sameString(action,"unlock")) { /* user probably didnt type in the right cachebuster cb= parm, we will supply it. */ cgiVarSet("cb",oldRandState); } reqRandState = cgiUsualString("cb",""); /* get cb (cache-buster), ignores request, defaults to main display page */ if (!sameString(reqRandState,oldRandState)) { printf("req != old. \n\n req=%s, old=%s \n\n",reqRandState,oldRandState); action = cloneString("display"); } /* ---- Push Queue ----- */ if (sameString(action,"display")) { doDisplay(); } else if (sameString(action,"add")) { doAdd(); } else if (sameString(action,"edit")) { doEdit(); } else if (sameString(action,"post")) { doPost(); } else if (sameString(action,"promote")) { doPromote(); } else if (sameString(action,"demote")) { doDemote(); } else if (sameString(action,"top")) { doTop(); } else if (sameString(action,"bottom")) { doBottom(); } else if (sameString(action,"pushDone")) { doPushDone(); } else if (sameString(action,"demoteColumn" )) { doDemoteColumn(); } else if (sameString(action,"hideColumn" )) { doHideColumn(); } else if (sameString(action,"promoteColumn")) { doPromoteColumn(); } else if (sameString(action,"showAllCol" )) { doShowAllColumns(); } else if (sameString(action,"showColumn" )) { doShowColumn(); } else if (sameString(action,"showDefaultCol" )) { doShowDefaultColumns(); } else if (sameString(action,"showMonths" )) { doShowMonths(); } else if (sameString(action,"showSizes" )) { doShowSizes(); } else if (sameString(action,"transfer" )) { doTransfer(); } else if (sameString(action,"transferTo" )) { doTransferTo(); } else if (sameString(action,"showGateway" )) { doShowGateway(); } else if (sameString(action,"unlock" )) { doUnlock(); } else if (sameString(action,"setSize" )) { doSetSize(); } else { safef(msg,sizeof(msg),"action='%s' is invalid!
\n",action); doMsg(); } oldRandState=newRandState; saveMyUser(); releaseLock(); sqlDisconnect(&conn); sqlDisconnect(&conn2); } int main(int argc, char *argv[], char *env[]) /* Process command line if any. */ { assert(e_NUMCOLS == ArraySize(colName)); assert(e_NUMCOLS == ArraySize(colHdr)); if (!cgiIsOnWeb()) { warn("This is a CGI script - attempting to fake environment from command line"); cgiSpoof(&argc, argv); } saveEnv = env; curtime = time (NULL); /* Get the current time. */ loctime = localtime (&curtime); /* Convert it to local time representation. */ srand( (unsigned)time( NULL ) ); /* Set seed (initial seed) off clock (not the best quality random input ;) */ uname(&utsName); ZeroVar(&myUser); database = cfgOption("pq.db" ); host = cfgOption("pq.host" ); user = cfgOption("pq.user" ); password = cfgOption("pq.password"); /* workaround for name-collision on form.action now as form._action on form */ action = cgiUsualString("_action","display"); /* get action, defaults to display of push queue */ action = cgiUsualString("action",action); if (sameString(action,"xpost")) { crossPost = TRUE; /* are we doing cross-post from dev to beta (or vice versa)? */ action = "post"; } /* initCgiInput() is not exported in cheapcgi.h, but it should get called by cgiUsualString So it will find all input regardless of Get/Put/Post/etc and make available as cgivars */ if (sameString(action,"releaseLog")) { doDrawReleaseLog(FALSE); return 0; } if (sameString(action,"encodeReleaseLog")) { doDrawReleaseLog(TRUE); return 0; } if (sameString(action,"releaseLogPush")) { htmShell(TITLE, doReleaseLogPush, NULL); return 0; } qaUser = findCookieData("qapushq"); /* will also cause internal structures to load cookie data */ if ((qaUser == NULL) || (sameString(qaUser,""))) { if (!sameString(action,"postLogin")) action = cloneString("login"); } if (sameString(action,"login")) { htmShell(TITLE, doLogin, NULL); } else if (sameString(action,"postLogin")) { doPostLogin(); /* cant start htmShell until cookie is set */ } else if (sameString(action,"reset")) { doCookieReset(); /* cant start htmShell until cookie is re-set */ } /* The help screens open in a separate window and don't hurt anything. Only displays text. Ignore cb. */ else if (sameString(action,"showDisplayHelp" )) { htmShell(TITLE, doShowDisplayHelp , NULL); } else if (sameString(action,"showEditHelp" )) { htmShell(TITLE, doShowEditHelp , NULL); } else if (sameString(action,"showSizesHelp" )) { htmShell(TITLE, doShowSizesHelp , NULL); } else { htmShell(TITLE, doMiddle, NULL); } return 0; }