diff --git a/nmdc_server/api.py b/nmdc_server/api.py index 636ceac6..525a7a61 100644 --- a/nmdc_server/api.py +++ b/nmdc_server/api.py @@ -1,7 +1,10 @@ +import json +import logging from io import BytesIO from typing import Any, Dict, List, Optional from uuid import UUID +import requests from fastapi import APIRouter, Depends, Header, HTTPException, Response, status from fastapi.responses import JSONResponse, PlainTextResponse from sqlalchemy.orm import Session @@ -728,12 +731,16 @@ async def update_submission( status_code=400, detail="This submission is currently being edited by a different user.", ) - + # Create Github issue when metadata is being submitted + if ( + submission.status == "in-progress" + and body_dict.get("status", None) == "Submitted- Pending Review" + ): + create_github_issue(submission, user) # Merge the submission metadata dicts submission.metadata_submission = ( submission.metadata_submission | body_dict["metadata_submission"] ) - # Update permissions and status iff the user is an "owner" if current_user_role and current_user_role.role == models.SubmissionEditorRole.owner: new_permissions = body_dict.get("permissions", None) @@ -747,6 +754,79 @@ async def update_submission( return submission +def create_github_issue(submission, user): + settings = Settings() + gh_url = str(settings.github_issue_url) + token = settings.github_authentication_token + assignee = settings.github_issue_assignee + # If the settings for issue creation weren't supplied return, no need to do anything further + if gh_url == None or token == None: + return + + # Gathering the fields we want to display in the issue + headers = {"Authorization": f"Bearer {token}", "Content-Type": "text/plain; charset=utf-8"} + studyform = submission.metadata_submission["studyForm"] + contextform = submission.metadata_submission["contextForm"] + multiomicsform = submission.metadata_submission["multiOmicsForm"] + pi = studyform["piName"] + piorcid = studyform["piOrcid"] + datagenerated = "Yes" if contextform["dataGenerated"] else "No" + omicsprocessingtypes = ", ".join(multiomicsform["omicsProcessingTypes"]) + sampletype = ", ".join(submission.metadata_submission["templates"]) + sampledata = submission.metadata_submission["sampleData"] + numsamples = 0 + for key in sampledata: + numsamples = max(numsamples, len(sampledata[key])) + + # some variable data to supply depending on if data has been generated or not + data_ids = [] + if contextform["dataGenerated"]: + data_ids = [ + "NCBI ID: " + multiomicsform["NCBIBioProjectId"], + "GOLD ID: " + multiomicsform["GOLDStudyId"], + "Alternative IDs/Names: " + ", ".join(multiomicsform["alternativeNames"]), + ] + + else: + data_ids = [ + "JGI IDs: " + multiomicsform["JGIStudyId"], + "EMSL IDs: " + multiomicsform["studyNumber"], + "Alternative IDs/Names: " + ", ".join(multiomicsform["alternativeNames"]), + ] + + # assemble the body of the API request + body_lis = [ + f"Submitter: {user.name}, {user.orcid}", + f"Submission ID: {submission.id}", + f"Has data been generated: {datagenerated}", + f"PI name: {pi}", + f"PI orcid: {piorcid}", + "Status: Submitted -Pending Review", + f"Data types: {omicsprocessingtypes}", + f"Sample type:{sampletype}", + f"Number of samples:{numsamples}", + ] + data_ids + body_string = " \n ".join(body_lis) + payload_dict = { + "title": f"NMDC Submission: {submission.id}", + "body": body_string, + "assignees": [assignee], + } + + payload = json.dumps(payload_dict) + + # make request and log an error or success depending on reply + res = requests.post(url=gh_url, data=payload, headers=headers) + if res.status_code != 201: + logging.error(f"Github issue creation failed with code {res.status_code}") + logging.error(res.reason) + else: + logging.info(f"Github issue creation successful with code {res.status_code}") + logging.info(res.reason) + + return res + + @router.delete( "/metadata_submission/{id}", tags=["metadata_submission"], diff --git a/nmdc_server/config.py b/nmdc_server/config.py index 1669e1af..43854f32 100644 --- a/nmdc_server/config.py +++ b/nmdc_server/config.py @@ -67,6 +67,11 @@ class Settings(BaseSettings): # CORS settings necessary for allowing request from Field Notes app cors_allow_origins: Optional[str] = None # comma separated list of allowed origins + # Github Issue creation settings. Both are required for automated issue creation. + github_issue_url: Optional[str] = None + github_authentication_token: Optional[str] = None + github_issue_assignee: Optional[str] = None + @property def current_db_uri(self) -> str: if self.environment == "testing":