def old_upload(local_path): """ OBSOLETE Upload file to incoming folder. :param local_path: :return: """ ProxyIP = config_get("ProxyIP") ProxyUsername = config_get("ProxyUsername") ProxyPassword = config_get("ProxyPassword") LORISHostIP = config_get("LORISHostIP") LORISHostUsername = config_get("LORISHostUsername") LORISHostPassword = config_get("LORISHostPassword") Client = LORIS_helper.getProxySSHClient( ProxyIP, ProxyUsername, ProxyPassword, LORISHostIP, LORISHostUsername, LORISHostPassword, ) file_name = os.path.basename(local_path) LORIS_helper.uploadThroughClient(Client, "//data/incoming/" + file_name, local_path)
def check_online_status() -> bool: """ Quck to see if the online connection exist :return: """ from DICOMTransit.LORIS.helper import LORIS_helper """ # DNS check vs Google DNS host = "http://8.8.8.8" port = 53 timeout = 3 try: socket.setdefaulttimeout(timeout) test_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((host, port)) test_socket.close() except: return False """ # WWW check vs Google import urllib.request status_google = urllib.request.urlopen("https://google.com").getcode() if not LORIS_helper.is_response(status_google, 200): return False # WWW check vs CNBP.ca status_cnbp = urllib.request.urlopen("http://www.cnbp.ca").getcode() if not LORIS_helper.is_response(status_cnbp, 200): return False else: return True
def process_upload_response(response): """ Check the upload response and then try to extract the process ID and UploadID :param response: :return: """ # Check if it is 403: permission error. if LORIS_helper.is_response(response.status_code, 403): warning_string = "The credential in the configuration for uploading to LORIS is incorrect, you do not have the credential to upload files!" logger.critical(warning_string) raise ValueError(warning_string) # Check for when the response is properly 200. elif LORIS_helper.is_response(response.status_code, 202): logger.info("Status Code: 202 received properly.") logger.info("Attempting to decode the JSON response:") # Convert to JSON. json_response = response.json() """ The Keys Will return: MRI upload ID Status Processes: """ # If there is mri upload ID, return it, other wise, do not return. if "processes" in json_response: # fixme: should attempt ot extract not only MRI_upload ID but also the process ID to return return 0 elif "mri_upload_id" in json_response: upload_id = json_response["mri_upload_id"] logger.debug( f"Successfully uploaded and server returned 202 with Upload ID of:{upload_id}" ) return upload_id else: warning_string = "Successfully uploaded and server returned 202, but returned JSON does not contain 'mri_upload_id'" logger.error(warning_string) raise ValueError(warning_string) # other. non 200 response. elif not LORIS_helper.is_response(response.status_code, 202): warning_string = f"Upload process has returned a non-202 RESPONSE. Status code returned is {response.status_code}" logger.critical(warning_string) raise ValueError(warning_string) else: warning_string = "Unanticipated status code condition encountered." logger.error(warning_string) raise UnboundLocalError(warning_string)
def login(): """ Logs into LORIS using the stored credential. Must use PyCurl as Requests is not working. :return: BOOL if or not it is successful. also, the JSON token that is necessary to conduct further transactions. """ from DICOMTransit.settings import config_get username = config_get("LORISusername") password = config_get("LORISpassword") data = json.dumps({"username": username, "password": password}) # Login URL url = config_get("LORISurl") if type(url) is furl: updated_url = url.url + "login" else: updated_url = url + "login" # requests style login # NOT WORKING! r = requests.post(updated_url, data=data) logger.debug(str(r.status_code) + r.reason) response_json = r.json() return LORIS_helper.is_response(r.status_code, 200), response_json.get("token")
def checkDCCIDExist(token, proposed_DCCID): """ Check if Site/Study already contain the PSCID :param token: :param proposed_DCCID: :return: True/False on if DCCID exist, PSCID if it exist. """ from DICOMTransit.LORIS.validate import LORIS_validation logger.debug("Checking if DCCID exist: " + str(proposed_DCCID)) if not LORIS_validation.validate_DCCID(proposed_DCCID): raise ValueError("DCCID is not valid!") # @todo: This area has projects/loris dependency. Refactor to enable multiple projects handling. response, JSON = LORIS_query.getCNBP( token, r"candidates/" + str(proposed_DCCID)) response_success = LORIS_helper.is_response(response, 200) if not response_success: logger.error(f"FAILED log response: {str(response)}") return response_success, None if JSON is not None: # only try to decode if response is not empty! meta = JSON.get("Meta") PSCID = meta.get("PSCID") return True, PSCID else: return False, None
def delete_study(StudyUID: str) -> bool: """ API to delete subject from the production Orthanc instance. :param StudyUID: :return: successful deletion status. """ credential = get_prod_orthanc_credentials() reseponse_code, _ = orthanc_query.deleteOrthanc(f"studies/{StudyUID}", credential) return LORIS_helper.is_response(reseponse_code, 200)
def test_deleteStudies(self): list_subjects = self.test_getStudies() patients_url = urllib.parse.urljoin(UT_DevOrthanc.credential.url, "studies/") for subject in list_subjects: patient_url = urllib.parse.urljoin(patients_url, f"{subject}") reseponse_code, _ = orthanc_query.deleteOrthanc( patient_url, self.credential) assert LORIS_helper.is_response(reseponse_code, 200)
def get_list_of_subjects_noauth(orthanc_URL: str) -> List[str]: """ Get a list of subjects from a .env predefined orthanc server. :return: the lsit of all subjects in the orthanc server """ endpoint = urllib.parse.urljoin(orthanc_URL, "patients/") reseponse_code, list_subjects = orthanc_query.getOrthanc_noauth(endpoint) if not (LORIS_helper.is_response(reseponse_code, 200)): raise ConnectionError("LORIS server did not return list of subjects. ") return list_subjects
def uploadExamples(self): file_list = get_testdata_files("[Ss][Mm][Aa][Ll][Ll]") for file in file_list: print(file) upload_files = {"upload_file": open(file, "rb")} orthanc_instance_url = urllib.parse.urljoin( UT_DevOrthanc.credential.url, "instances") status, r = orthanc_query.postOrthanc(orthanc_instance_url, UT_DevOrthanc.credential, upload_files) assert LORIS_helper.is_response(status, 200) assert r.json()
def check_prod_orthanc_status() -> bool: """ Check the orthanc status to ensure that it is online. :return: """ credential = get_prod_orthanc_credentials() try: endpoint = urllib.parse.urljoin(credential.url, "studies") reseponse_code, _ = orthanc_query.getOrthanc(endpoint, credential) success = LORIS_helper.is_response(reseponse_code, 200) except: # in case any thing goes wrong return False return success
def visit_number_extraction(string: str): """ A wrapper for number_extraction by calling it on a string and then return the latest one. Used to deal with visitnumber list. :param string: :return: """ number_extracted = LORIS_helper.number_extraction(string) # return last number from the timepoint string: usually it should be V2 or T3 things like that. if len(number_extracted) > 1: return number_extracted[len(number_extracted) - 1] else: return number_extracted[0]
def test_number_extraction(self): Prefix = "V" numbers = [1, 2, 3, 9, 10, 11, 12, 100, 101, 102] timepoints = [] for number in numbers: timepoints.append(Prefix + str(number)) DualList = zip(numbers, timepoints) for tupleItem in DualList: assert str(tupleItem[0]) == LORIS_helper.number_extraction( tupleItem[1])[0]
def deleteCandidateCNBP(DCCID, PSCID): # @todo: this should really be done through API. But Currently LORIS does not offer such API. # NOTE! If you EVER get NULL coalesce not recognized error, make sure that the PHP version being called from # the SSH session is 7+ or else. We had a major issue where the PHP version from SSH session being LOWER # than the .bashrc profile imported edition. Also keep in mind that EVEN if .bashrc import this, it MOST LIKELY # will not apply to the SSH session! LORISHostPassword = config_get("LORISHostPassword") LORISHostUsername = config_get("LORISHostUsername") LORISHostIP = config_get("LORISHostIP") DeletionScript = config_get("DeletionScript") # NOTE! If you EVER get NULL coalesce not recognized error, make sure that the PHP version being called from # the SSH session is 7+ or else. We had a major issue where the PHP version from SSH session being LOWER # than the bashrc profile imported edition. Also keep in mind that EVEN if .bashrc import this, it MOST LIKELY # will not apply to the SSH session! command_string = f"/opt/rh//rh-php70/root/usr/bin/php {DeletionScript} delete_candidate {str(DCCID)} {PSCID} confirm" logger.debug(command_string) # Establish connection to client. Client = LORIS_helper.getProxySSHClient( ProxyIP, ProxyUsername, ProxyPassword, LORISHostIP, LORISHostUsername, LORISHostPassword, ) # Execute the command LORIS_helper.triggerCommand(Client, command_string) # Close the client. Client.close()
def get_all_subject_StudyUIDs( credential: orthanc_credential) -> List[List[str]]: """ Get a list of STUDIES from a .env predefined orthanc server. :return: the list of all studies in the orthanc server """ endpoint = urllib.parse.urljoin(credential.url, "studies/") reseponse_code, list_studies = orthanc_query.getOrthanc( endpoint, credential) if not LORIS_helper.is_response(reseponse_code, 200): raise ConnectionError("LORIS server did not return list of subjects. ") return list_studies
def createCandidate(token, project, birth_date, gender): """ Create a candidate with a provided project information. This assumes that the PSCID and DCCIDs are automaticly assigned! :param token :param birth_date: Birth date MUST Be in YYYY-MM-DD format! :param gender: Gender must be Male or Female! :param project: :return: DCCID """ logger.debug(f"Creating CNBP Candidates belong to project: {project}") Candidate = {} from DICOMTransit.LORIS.validate import LORIS_validation if not LORIS_validation.validate_birth_date_loris( birth_date ) or not LORIS_validation.validate_gender( gender ): # not LORIS_validation.validate_project(project) or #@todo fix this project validation part during creation. logger.error( "Non-compliant PSCID component detected. Aborting PSCID creation " ) return False, None Candidate["Project"] = project Candidate["EDC"] = birth_date # Candidate['PSCID'] = proposed_PSCID Now auto sequence. Candidate["DoB"] = birth_date Candidate["Gender"] = gender Candidate["Site"] = config_get("institutionName") data = {"Candidate": Candidate} data_json = json.dumps(data) response_code, response = LORIS_query.postCNBP(token, "candidates/", data_json) if not LORIS_helper.is_response(response_code, 201): return False, None, None elif response is not None: # only try to decode if response is not empty! response_json = response.json() meta = response_json.get("Meta") CandID = meta.get("CandID") return True, CandID else: return False, None
def get_StudyUID_zip(orthanc_URL_with_StudyUID: str, credential: orthanc_credential) -> str: """ Obtain the actual zip files of the subject based on the StudyUID given and unzip them to a temporary folder, and return it. :param orthanc_URL_with_StudyUID: :return: the temporary folder object which contain the reference to the folder in the .name attribute """ status, local_zip_file_path = orthanc_query.getZipFromOrthanc( orthanc_URL_with_StudyUID, credential) if not (LORIS_helper.is_response(status, 200)): raise ConnectionError("Orthanc is not reachable!") if not os.path.exists(local_zip_file_path): raise FileNotFoundError( "Local zip file to be uploaded has not been found!") logger.info("Subject ZIP downloaded.") return local_zip_file_path
def new_trigger_insertion(DCCID: int, VisitLabel: str, filename: str, mri_upload_id: int) -> int: """ Trigger the insertion of the subject files and then return the process_id which can be checked later on. :param DCCID: :param VisitLabel: :param filename: :param mri_upload_id: :return: """ # POST / candidates /$CandID /$VisitLabel / dicoms /$Filename / endpoint = f"candidates/{DCCID}/{VisitLabel}/dicoms/{filename}" # Get token. response_success, token = LORIS_query.login() if not response_success: raise ConnectionError import json request_dictionary = { "process_type": "mri_upload", "Filename": filename, "mri_upload_id": mri_upload_id, } # the request in json format ready for payload. request_json = json.dumps(request_dictionary) # Post the requests. status_code, response = LORIS_query.postCNBP(token, endpoint, request_json) process_id = None if LORIS_helper.is_response(status_code, 202): response_dict = response.json() if ("processes" in response_dict and "process_id" in response_dict["processes"][0]): process_id = int(response_dict["processes"][0]["process_id"]) return process_id
def createTimepoint(token, DCCID, time_point) -> bool: """ Create a timepoint of the given DCCID subject based on the timepoint provided. :param token: :param DCCID: :param time_point: :return: """ endpoint = r"/candidates/" + str(DCCID) + r"/" + time_point MetaData = { "CandID": DCCID, "Visit": time_point, "Site": config_get("institutionName"), "Battery": "CNBP", } # default to CNBP for NOW Meta = {"Meta": MetaData} JSON = json.dumps(Meta) status_code, _ = LORIS_query.putCNBP(token, endpoint, JSON) success = LORIS_helper.is_response( status_code, 201) # 201 signify successufl subject timepoint creation! # response should be null! return success