ba33f2c600399d5b4b97dd5fd987ed2db3c891ba chmalee Tue May 19 13:40:42 2026 -0700 myVariants related fixes from code review. Standardize how the code determines we are about to do something myVariants related by #defining some strings and using sameOk to check for them, remove a dead code block, and have hgc use autoSql to load the myVariants item rather than check the raw sql result, refs #37528 diff --git src/hg/lib/myVariantsShare.c src/hg/lib/myVariantsShare.c index 252c589d3ce..eedf1f82fc0 100644 --- src/hg/lib/myVariantsShare.c +++ src/hg/lib/myVariantsShare.c @@ -1,369 +1,329 @@ /* myVariantsShare.c was originally generated by the autoSql program, which also * generated myVariantsShare.h and myVariantsShare.sql. This module links the database and * the RAM representation of objects. */ #include "common.h" #include "linefile.h" #include "dystring.h" #include "jksql.h" #include "myVariantsShare.h" #include "htmshell.h" #include "jsonParse.h" #include "jsonWrite.h" #include "errCatch.h" char *myVariantsShareCommaSepFieldNames = "id,ownerUser,shareToken,project,db,permission,targetUser,label,createdAt"; void myVariantsShareStaticLoad(char **row, struct myVariantsShare *ret) /* Load a row from myVariantsShare table into ret. The contents of ret will * be replaced at the next call to this function. */ { ret->id = sqlUnsigned(row[0]); ret->ownerUser = row[1]; ret->shareToken = row[2]; ret->project = row[3]; ret->db = row[4]; ret->permission = sqlUnsigned(row[5]); ret->targetUser = row[6]; ret->label = row[7]; ret->createdAt = row[8]; } struct myVariantsShare *myVariantsShareLoadByQuery(struct sqlConnection *conn, char *query) /* Load all myVariantsShare from table that satisfy the query given. * Where query is of the form 'select * from example where something=something' * or 'select example.* from example, anotherTable where example.something = * anotherTable.something'. * Dispose of this with myVariantsShareFreeList(). */ { struct myVariantsShare *list = NULL, *el; struct sqlResult *sr; char **row; sr = sqlGetResult(conn, query); while ((row = sqlNextRow(sr)) != NULL) { el = myVariantsShareLoad(row); slAddHead(&list, el); } slReverse(&list); sqlFreeResult(&sr); return list; } void myVariantsShareSaveToDb(struct sqlConnection *conn, struct myVariantsShare *el, char *tableName, int updateSize) /* Save myVariantsShare as a 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. Arrays of native types are * converted to comma separated strings and loaded as such, User defined types are * inserted as NULL. This function automatically escapes quoted strings for mysql. */ { struct dyString *update = dyStringNew(updateSize); sqlDyStringPrintf(update, "insert into %s values ( %u,'%s','%s','%s','%s',%u,'%s','%s','%s')", tableName, el->id, el->ownerUser, el->shareToken, el->project, el->db, el->permission, el->targetUser, el->label, el->createdAt); sqlUpdate(conn, update->string); dyStringFree(&update); } struct myVariantsShare *myVariantsShareLoad(char **row) /* Load a myVariantsShare from row fetched with select * from myVariantsShare * from database. Dispose of this with myVariantsShareFree(). */ { struct myVariantsShare *ret; AllocVar(ret); ret->id = sqlUnsigned(row[0]); ret->ownerUser = cloneString(row[1]); ret->shareToken = cloneString(row[2]); ret->project = cloneString(row[3]); ret->db = cloneString(row[4]); ret->permission = sqlUnsigned(row[5]); ret->targetUser = cloneString(row[6]); ret->label = cloneString(row[7]); ret->createdAt = cloneString(row[8]); return ret; } struct myVariantsShare *myVariantsShareLoadAll(char *fileName) /* Load all myVariantsShare from a whitespace-separated file. * Dispose of this with myVariantsShareFreeList(). */ { struct myVariantsShare *list = NULL, *el; struct lineFile *lf = lineFileOpen(fileName, TRUE); char *row[9]; while (lineFileRow(lf, row)) { el = myVariantsShareLoad(row); slAddHead(&list, el); } lineFileClose(&lf); slReverse(&list); return list; } struct myVariantsShare *myVariantsShareLoadAllByChar(char *fileName, char chopper) /* Load all myVariantsShare from a chopper separated file. * Dispose of this with myVariantsShareFreeList(). */ { struct myVariantsShare *list = NULL, *el; struct lineFile *lf = lineFileOpen(fileName, TRUE); char *row[9]; while (lineFileNextCharRow(lf, chopper, row, ArraySize(row))) { el = myVariantsShareLoad(row); slAddHead(&list, el); } lineFileClose(&lf); slReverse(&list); return list; } struct myVariantsShare *myVariantsShareCommaIn(char **pS, struct myVariantsShare *ret) /* Create a myVariantsShare out of a comma separated string. * This will fill in ret if non-null, otherwise will * return a new myVariantsShare */ { char *s = *pS; if (ret == NULL) AllocVar(ret); ret->id = sqlUnsignedComma(&s); ret->ownerUser = sqlStringComma(&s); ret->shareToken = sqlStringComma(&s); ret->project = sqlStringComma(&s); ret->db = sqlStringComma(&s); ret->permission = sqlUnsignedComma(&s); ret->targetUser = sqlStringComma(&s); ret->label = sqlStringComma(&s); ret->createdAt = sqlStringComma(&s); *pS = s; return ret; } void myVariantsShareFree(struct myVariantsShare **pEl) /* Free a single dynamically allocated myVariantsShare such as created * with myVariantsShareLoad(). */ { struct myVariantsShare *el; if ((el = *pEl) == NULL) return; freeMem(el->ownerUser); freeMem(el->shareToken); freeMem(el->project); freeMem(el->db); freeMem(el->targetUser); freeMem(el->label); freeMem(el->createdAt); freez(pEl); } void myVariantsShareFreeList(struct myVariantsShare **pList) /* Free a list of dynamically allocated myVariantsShare's */ { struct myVariantsShare *el, *next; for (el = *pList; el != NULL; el = next) { next = el->next; myVariantsShareFree(&el); } *pList = NULL; } void myVariantsShareOutput(struct myVariantsShare *el, FILE *f, char sep, char lastSep) /* Print out myVariantsShare. Separate fields with sep. Follow last field with lastSep. */ { fprintf(f, "%u", el->id); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->ownerUser); if (sep == ',') fputc('"',f); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->shareToken); if (sep == ',') fputc('"',f); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->project); if (sep == ',') fputc('"',f); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->db); if (sep == ',') fputc('"',f); fputc(sep,f); fprintf(f, "%u", el->permission); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->targetUser); if (sep == ',') fputc('"',f); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->label); if (sep == ',') fputc('"',f); fputc(sep,f); if (sep == ',') fputc('"',f); fprintf(f, "%s", el->createdAt); if (sep == ',') fputc('"',f); fputc(lastSep,f); } /* -------------------------------- End autoSql Generated Code -------------------------------- */ struct myVariantsShare *myVariantsCreateShare(struct sqlConnection *conn, char *ownerUser, char *project, char *db, int permission, char *targetUser, char *label) /* Create a new share record. Returns the share with token and id filled in. * Free with myVariantsShareFree. */ { char *token = makeRandomKey(288); /* 288 bits -> 48 base64 URL-safe chars */ struct dyString *dy = sqlDyStringCreate( "INSERT INTO myVariantsShares (ownerUser, shareToken, project, db, permission, targetUser, label)" " VALUES ('%s', '%s', '%s', '%s', %d,", ownerUser, token, project, db, permission); if (targetUser != NULL) sqlDyStringPrintf(dy, " '%s',", targetUser); else sqlDyStringPrintf(dy, " NULL,"); if (label != NULL) sqlDyStringPrintf(dy, " '%s')", label); else sqlDyStringPrintf(dy, " NULL)"); sqlUpdate(conn, dy->string); dyStringFree(&dy); struct myVariantsShare *share; AllocVar(share); share->id = sqlLastAutoId(conn); share->ownerUser = cloneString(ownerUser); share->shareToken = token; share->project = cloneString(project); share->db = cloneString(db); share->permission = permission; share->targetUser = cloneString(targetUser); share->label = cloneString(label); share->createdAt = cloneString(""); return share; } struct myVariantsShare *myVariantsGetShareByToken(struct sqlConnection *conn, char *token) /* Look up a single share by token. Returns NULL if not found or token is malformed. */ { if (token == NULL || strlen(token) != MYVAR_TOKEN_LENGTH) return NULL; char query[512]; sqlSafef(query, sizeof(query), "SELECT * FROM myVariantsShares WHERE shareToken='%s'", token); struct sqlResult *sr = sqlGetResult(conn, query); char **row = sqlNextRow(sr); struct myVariantsShare *share = NULL; if (row != NULL) share = myVariantsShareLoad(row); sqlFreeResult(&sr); return share; } struct myVariantsShare *myVariantsGetSharesForOwner(struct sqlConnection *conn, char *ownerUser, char *db) /* Get all shares created by this user for the given assembly. */ { char query[512]; sqlSafef(query, sizeof(query), "SELECT * FROM myVariantsShares WHERE ownerUser='%s' AND db='%s'" " ORDER BY createdAt DESC", ownerUser, db); return myVariantsShareLoadByQuery(conn, query); } struct myVariantsShare *myVariantsGetSharesForUser(struct sqlConnection *conn, char *targetUser, char *db) /* Get all shares targeted at this user for the given assembly. */ { char query[512]; sqlSafef(query, sizeof(query), "SELECT * FROM myVariantsShares WHERE targetUser='%s' AND db='%s'" " ORDER BY createdAt DESC", targetUser, db); return myVariantsShareLoadByQuery(conn, query); } boolean myVariantsRevokeShare(struct sqlConnection *conn, char *shareToken, char *ownerUser) /* Delete a share record. ownerUser must match the share's owner. * Returns TRUE if a row was deleted, FALSE if not found or not owner. */ { char query[512]; sqlSafef(query, sizeof(query), "SELECT count(*) FROM myVariantsShares WHERE shareToken='%s' AND ownerUser='%s'", shareToken, ownerUser); int count = sqlQuickNum(conn, query); if (count == 0) return FALSE; sqlSafef(query, sizeof(query), "DELETE FROM myVariantsShares WHERE shareToken='%s' AND ownerUser='%s'", shareToken, ownerUser); sqlUpdate(conn, query); return TRUE; } char *myVariantsShareCartValue(struct myVariantsShare *share) /* Build JSON cart value string from a share record. * Caller must freeMem the result. */ { struct jsonWrite *jw = jsonWriteNew(); jsonWriteObjectStart(jw, NULL); jsonWriteString(jw, "owner", share->ownerUser); jsonWriteString(jw, "project", share->project); jsonWriteString(jw, "db", share->db); jsonWriteNumber(jw, "permission", share->permission); if (isNotEmpty(share->label)) jsonWriteString(jw, "label", share->label); jsonWriteObjectEnd(jw); char *result = cloneString(jw->dy->string); jsonWriteFree(&jw); return result; } -boolean myVariantsParseShareCartValue(char *val, char **retOwner, - char **retProject, char **retDb, int *retPermission, char **retLabel) -/* Parse a JSON cart value string back into components. Returns FALSE on bad format. - * retOwner, retProject, retDb, retLabel are cloneString'd; caller must free. - * retLabel may be NULL; pass NULL to skip. */ -{ -if (isEmpty(val)) - return FALSE; -/* jsonParse errAborts on malformed input; catch so a malicious cart value - * can't take down a session-load or page render. */ -struct jsonElement *json = NULL; -struct errCatch *ec = errCatchNew(); -if (errCatchStart(ec)) - json = jsonParse(val); -errCatchEnd(ec); -boolean parseFailed = ec->gotError; -errCatchFree(&ec); -if (parseFailed || json == NULL) - return FALSE; -char *owner = jsonOptionalStringField(json, "owner", NULL); -char *project = jsonOptionalStringField(json, "project", NULL); -char *db = jsonOptionalStringField(json, "db", NULL); -if (owner == NULL || project == NULL || db == NULL) - return FALSE; -if (retOwner) - *retOwner = cloneString(owner); -if (retProject) - *retProject = cloneString(project); -if (retDb) - *retDb = cloneString(db); -if (retPermission) - { - struct jsonElement *permEl = jsonFindNamedField(json, "", "permission"); - *retPermission = (permEl != NULL) ? (int)jsonNumberVal(permEl, "permission") : 0; - } -if (retLabel) - *retLabel = cloneString(jsonOptionalStringField(json, "label", "")); -return TRUE; -} -