0cfb3c37fdb1de8873336f9d6f95b3422a465964 hiram Sun Aug 9 10:45:26 2026 -0700 in the case of an equivalent available browser for a user browser build request, alert the user to the existence of the equivalent refs #31811 diff --git src/hg/utils/otto/userRequests/ottoRequest.py src/hg/utils/otto/userRequests/ottoRequest.py index 80171c95fdb..789ba169c1a 100755 --- src/hg/utils/otto/userRequests/ottoRequest.py +++ src/hg/utils/otto/userRequests/ottoRequest.py @@ -168,30 +168,43 @@ m2 = re.match(r"; betterName: '([^']*)'(.*)$", rest, re.DOTALL) if m2: betterName = m2.group(1) rest = m2.group(2) m3 = re.match(r"; comment: '(.*)'\s*$", rest, re.DOTALL) if m3: userComment = m3.group(1) else: userComment = rest.lstrip('; ') return name, betterName, userComment +def browserUrl(db): + """Return the hgTracks URL for a browser db -- a GenArk hub accession + (GC[AF]_...) needs the mirrored hub.txt gbdb path, a UCSC native db + just needs db=. Mirrors asmRequestWatch.sh phase 6's URL + construction (accessionToPath() + hubTxt).""" + m = re.match(r'^(GC[AF])_(\d{3})(\d{3})(\d{3})', db) + if m: + gcX, d0, d1, d2 = m.groups() + gbDbPath = f"/gbdb/genark/{gcX}/{d0}/{d1}/{d2}/{db}/hub.txt" + return f"https://genome.ucsc.edu/cgi-bin/hgTracks?genome={db}&hubUrl={gbDbPath}" + return f"https://genome.ucsc.edu/cgi-bin/hgTracks?db={db}" + + def sendMail(toAddr, subject, body, fromAddr=None, bccAddr=None, bounceAddr=None): """Send email via /usr/sbin/sendmail. If fromAddr is provided it is used as the envelope sender (-f) and the From: header so that bounces return to that address. If bccAddr is provided, sendmail -t reads it from the header, delivers a copy, and strips the Bcc: line before transmission.""" headers = f"To: {toAddr}\nSubject: {subject}" if bccAddr: headers = f"Bcc: {bccAddr}\n{headers}" if fromAddr: headers = (f"From: {fromAddr}\n" f"Reply-To: {fromAddr}\n" f"Return-Path: {fromAddr}\n" f"{headers}") message = f"{headers}\n\n{body}\n" @@ -240,33 +253,63 @@ for req in pending: reqType = req['requestType'] bccAddr = BCC_BY_TYPE.get(reqType) if not bccAddr: print(f"Warning: unknown requestType '{reqType}' for" f" request #{req['id']}, skipping", file=sys.stderr) continue userEmail = req.get('email', '') if not userEmail: print(f"Warning: no user email for request #{req['id']}," f" skipping", file=sys.stderr) continue + # findGenome.c:apiAssemblyRequest() sets toDb != fromDb when + # asmAlias already maps the requested asmId to a browser we have + # -- no build is needed, so send the "already available" + # acknowledgement here and close out the row now instead of + # handing it to asmRequestWatch.sh, which would otherwise wait + # forever for a build that will never happen. + alreadyExists = (reqType == 'assembly' and req['toDb'] + and req['toDb'] != req['fromDb']) + subject = (f"UCSC Genome Browser: your {reqType}" f" request has been received") - if reqType == 'assembly': + if alreadyExists: + subject = "UCSC Genome Browser: your assembly request is already available" + name, betterName, userComment = parseAssemblyComment(req['comment']) + body = ( + f"Good news -- the assembly you requested already has an\n" + f"equivalent browser available, so no new build is needed.\n" + f"\n" + f"name: '{name}'\n" + f"email: '{userEmail}'\n" + f"requested asmId: '{req['fromDb']}'\n" + f"existing browser: '{req['toDb']}'\n" + f"comment: '{userComment.rstrip()}'\n" + f"date: '{req['requestTime']}'\n" + f"\n" + f"View it here:\n" + f" {browserUrl(req['toDb'])}\n" + f"\n" + f"If this is insufficient for your research purpose, please let us know in response to this email.\n" + f"\n" + f"-- UCSC Genome Browser\n" + ) + elif reqType == 'assembly': name, betterName, userComment = parseAssemblyComment(req['comment']) body = ( f"Your assembly request has been received and is being\n" f"processed.\n" f"\n" f"name: '{name}'\n" f"email: '{userEmail}'\n" f"asmId: '{req['fromDb']}'\n" f"betterName: '{betterName}'\n" f"comment: '{userComment.rstrip()}'\n" f"date: '{req['requestTime']}'\n" f"\n" f"Will advise when this assembly is available in the genome browser.\n" f"\n" f"-- UCSC Genome Browser\n" @@ -277,24 +320,30 @@ f"processed.\n" f"\n" f"Request details:\n" f" From: {req['fromDb']}\n" f" To: {req['toDb']}\n" f" Comment: {req['comment'].rstrip()}\n" f" Submitted: {req['requestTime']}\n" f"\n" f"Will advise when this alignment is available in the genome browser.\n" f"\n" f"-- UCSC Genome Browser\n" ) bitParts = ["gb", "aut", "o", "@", "uc", "sc.", "ed", "u"] if sendMail(userEmail, subject, body, fromAddr=NOTIFY_FROM, bccAddr=bccAddr, bounceAddr="".join(bitParts)): + if alreadyExists: + # resolved by asmAlias -- no build, close the row out now + hgsqlUpdate(dbHost, ottoDb, + f"UPDATE {ottoTable} SET status = 8, completeTime = NOW()" + f" WHERE id = {req['id']}") + else: hgsqlUpdate(dbHost, ottoDb, f"UPDATE {ottoTable} SET status = 1" f" WHERE id = {req['id']}") else: print(f"Failed to send notification for request #{req['id']}", file=sys.stderr) if __name__ == '__main__': main()