def detail_job(self, job_id, wait=False, timeout=30): """Get detailled information about a job API Endpoint: GET /jobs/{id} :param job_id: the id of the job :param wait: wait until the job is finished (default: False) :param timeout: stop waiting after x seconds (default: 30) :type: int :type wait: boolean :type timeout: 30 :return: the job data :rtype: Job :raises FossologyApiError: if the REST call failed """ response = self.session.get(f"{self.api}/jobs/{job_id}") if wait: if response.status_code == 200: job = Job.from_json(response.json()) if job.status == "Completed": logger.debug(f"Job {job_id} has completed") return job else: description = f"Error while getting details for job {job_id}" raise FossologyApiError(description, response) logger.debug(f"Waiting for job {job_id} to complete") time.sleep(timeout) response = self.session.get(f"{self.api}/jobs/{job_id}") if response.status_code == 200: logger.debug(f"Got details for job {job_id}") return Job.from_json(response.json()) else: description = f"Error while getting details for job {job_id}" raise FossologyApiError(description, response)
def create_folder(self, parent, name, description=None, group=None): """Create a new (sub)folder The name of the new folder must be unique under the same parent. Folder names are case insensitive. API Endpoint: POST /folders/{id} :param parent: the parent folder :param name: the name of the folder :param description: a meaningful description for the folder (default: None) :param group: the name of the group chosen to create the folder (default: None) :type parent: Folder() object :type name: str :type description: str :type group: string :return: the folder newly created (or already existing) - or None :rtype: Folder() object :raises FossologyApiError: if the REST call failed :raises AuthorizationError: if the user is not allowed to write in the folder or access the group """ headers = { "parentFolder": f"{parent.id}", "folderName": f"{name}", "folderDescription": f"{description}", } if group: headers["groupName"] = group response = self.session.post(f"{self.api}/folders", headers=headers) if response.status_code == 200: logger.info( f"Folder '{name}' already exists under the folder {parent.name} ({parent.id})" ) # Foldernames with similar letter but different cases # are not allowed in Fossology, compare with lower case existing_folder = [ folder for folder in self.folders if folder.name.lower() == name.lower() and folder.parent == parent.id ] if existing_folder: return existing_folder[0] description = f"Folder '{name}' exists but was not found under the folder {parent.name} ({parent.id})" raise FossologyApiError(description, response) elif response.status_code == 201: logger.info(f"Folder {name} has been created") return self.detail_folder(response.json()["message"]) elif response.status_code == 403: description = f"Folder creation {get_options(group, parent)}not authorized" raise AuthorizationError(description, response) else: description = f"Unable to create folder {name} under {parent}" raise FossologyApiError(description, response)
def get_self(self, name=None): """Perform the first API request and populate user variables API Endpoint: GET /users/self :return: the authenticated user's details :rtype: User :raises FossologyApiError: if the REST call failed :raises AuthenticationError: if the user couldn't be found """ if versiontuple(self.version) >= versiontuple("1.2.3"): response = self.session.get(f"{self.api}/users/self") if response.status_code == 200: user_agents = None user_details = response.json() if user_details.get("agents"): user_agents = Agents.from_json(user_details["agents"]) user = User.from_json(user_details) user.agents = user_agents return user else: description = "Error while getting details about authenticated user" raise FossologyApiError(description, response) else: if not name: description = "You need to provide a username to create an API session" raise AuthenticationError(description) self.users = self.list_users() for user in self.users: if user.name == name: self.user = user return self.user description = f"User {name} was not found on {self.host}" raise AuthenticationError(description)
def list_jobs(self, page_size=20, page=1, upload=None): """Get all available jobs API Endpoint: GET /jobs The answer is limited to the first page of 20 results by default :param page_size: the maximum number of results per page :param page: the number of pages to be retrieved :param upload: list only jobs of the given upload (default: None) :type page_size: int (default: 20) :type page: int (default: 1) :type upload: Upload :return: the jobs data :rtype: list of Job :raises FossologyApiError: if the REST call failed """ params = {} headers = {"limit": str(page_size), "page": str(page)} if upload: params["upload"] = upload.id response = self.session.get(f"{self.api}/jobs", params=params, headers=headers) if response.status_code == 200: jobs_list = list() for job in response.json(): jobs_list.append(Job.from_json(job)) return jobs_list else: description = "Getting the list of jobs failed" raise FossologyApiError(description, response)
def list_users(self): """ List all users from the Fossology instance API Endpoint: GET /users :return: the list of users :rtype: list of User :raises FossologyApiError: if the REST call failed """ response = self.session.get(f"{self.api}/users") if response.status_code == 200: users_list = list() for user in response.json(): if user.get("name") == "Default User": continue if user.get("email"): foss_user = User.from_json(user) agents = user.get("agents") if agents: foss_user.agents = Agents.from_json(agents) users_list.append(foss_user) return users_list else: description = f"Unable to get a list of users from {self.host}" raise FossologyApiError(description, response)
def detail_upload(self, upload_id: int, group: str = None, wait_time: int = 0) -> Upload: """Get detailled information about an upload API Endpoint: GET /uploads/{id} Get information about a given upload. If the upload is not ready wait another ``wait_time`` seconds or look at the ``Retry-After`` to determine how long the wait period shall be. If ``wait_time`` is 0, the time interval specified by the ``Retry-After`` header is used. The function stops trying after **10 attempts**. :Examples: >>> # Wait up to 20 minutes until the upload is ready >>> long_upload = detail_upload(1, 120) >>> # Wait up to 5 minutes until the upload is ready >>> long_upload = detail_upload(1, 30) :param upload_id: the id of the upload :param group: the group the upload shall belong to :param wait_time: use a customized upload wait time instead of Retry-After (in seconds, default: 0) :type upload_id: int :type group: string :type wait_time: int :return: the upload data :rtype: Upload :raises FossologyApiError: if the REST call failed :raises AuthorizationError: if the user can't access the group """ headers = {} if group: headers["groupName"] = group response = self.session.get(f"{self.api}/uploads/{upload_id}", headers=headers) if response.status_code == 200: logger.debug(f"Got details for upload {upload_id}") return Upload.from_json(response.json()) elif response.status_code == 403: description = f"Getting details for upload {upload_id} {get_options(group)}not authorized" raise AuthorizationError(description, response) elif response.status_code == 503: if not wait_time: wait_time = response.headers["Retry-After"] logger.debug( f"Retry GET upload {upload_id} after {wait_time} seconds: {response.json()['message']}" ) time.sleep(int(wait_time)) raise TryAgain else: description = f"Error while getting details for upload {upload_id}" raise FossologyApiError(description, response)
def list_groups(self) -> List: """Get the list of groups (accessible groups for user, all groups for admin) API Endpoint: GET /groups :return: a list of groups :rtype: list() :raises FossologyApiError: if the REST call failed """ if fossology.versiontuple( self.version) < fossology.versiontuple("1.2.1"): description = f"Endpoint /groups is not supported by your Fossology API version {self.version}" raise FossologyUnsupported(description) response = self.session.get(f"{self.api}/groups") if response.status_code == 200: groups_list = [] response_list = response.json() for group in response_list: single_group = Group.from_json(group) groups_list.append(single_group) return groups_list else: description = f"Unable to get a list of groups for {self.user.name}" raise FossologyApiError(description, response)
def delete_upload(self, upload, group=None): """Delete an upload API Endpoint: DELETE /uploads/{id} :param upload: the upload to be deleted :param group: the group name to chose while deleting the upload (default: None) :type upload: Upload :type group: string :raises FossologyApiError: if the REST call failed :raises AuthorizationError: if the user can't access the group """ headers = {} if group: headers["groupName"] = group response = self.session.delete(f"{self.api}/uploads/{upload.id}", headers=headers) if response.status_code == 202: logger.info(f"Upload {upload.id} has been scheduled for deletion") elif response.status_code == 403: description = ( f"Deleting upload {upload.id} {get_options(group)}not authorized" ) raise AuthorizationError(description, response) else: description = f"Unable to delete upload {upload.id}" raise FossologyApiError(description, response)
def _put_folder(self, action, folder, parent): """Copy or move a folder Internal function meant to be called by move_folder() or copy_folder() API Endpoint: PUT /folders/{id} :param action: "move" or "copy" :param action: string :param folder: the Folder to be moved or copied :type folder: Folder() object :param parent: the new parent folder :type parent: Folder() object :return: the updated folder :rtype: Folder() object :raises FossologyApiError: if the REST call failed """ headers = {"parent": str(parent.id), "action": action} response = self.session.put(f"{self.api}/folders/{folder.id}", headers=headers) if response.status_code == 202: logger.info( f"Folder {folder.name} has been {action}d to {parent.name}") return self.detail_folder(folder.id) else: description = f"Unable to {action} folder {folder.name} to {parent.name}" raise FossologyApiError(description, response)
def move_upload(self, upload, folder, group=None): """Move an upload to another folder API Endpoint: PATCH /uploads/{id} :param upload: the Upload to be copied in another folder :param folder: the destination Folder :param group: the group name to chose while changing the upload (default: None) :type upload: Upload :type folder: Folder :type group: string :raises FossologyApiError: if the REST call failed :raises AuthorizationError: if the user can't access the group or folder """ headers = {"folderId": str(folder.id)} if group: headers["groupName"] = group response = self.session.patch(f"{self.api}/uploads/{upload.id}", headers=headers) if response.status_code == 202: logger.info( f"Upload {upload.uploadname} has been moved to {folder.name}") elif response.status_code == 403: description = ( f"Moving upload {upload.id} {get_options(group, folder)}not authorized" ) raise AuthorizationError(description, response) else: description = f"Unable to move upload {upload.uploadname} to {folder.name}" raise FossologyApiError(description, response)
def update_folder(self, folder, name=None, description=None): """Update a folder's name or description The name of the new folder must be unique under the same parent. API Endpoint: PATCH /folders/{id} :param name: the new name of the folder (optional) :param description: the new description for the folder (optional) :type name: str :type description: str :return: the updated folder :rtype: Folder() object :raises FossologyApiError: if the REST call failed """ headers = dict() if name: headers["name"] = name if description: headers["description"] = description folders_api_path = f"{self.api}/folders/{folder.id}" response = self.session.patch(folders_api_path, headers=headers) if response.status_code == 200: folder = self.detail_folder(folder.id) logger.info(f"{folder} has been updated") return folder else: description = f"Unable to update folder {folder.id}" raise FossologyApiError(description, response)
def copy_upload(self, upload, folder): """Copy an upload in another folder API Endpoint: PUT /uploads/{id} :param upload: the Upload to be copied in another folder :param folder: the destination Folder :type upload: Upload :type folder: Folder :raises FossologyApiError: if the REST call failed """ headers = {"folderId": str(folder.id)} response = self.session.put(f"{self.api}/uploads/{upload.id}", headers=headers) if response.status_code == 202: logger.info( f"Upload {upload.uploadname} has been copied to {folder.name}") elif response.status_code == 403: description = f"Copy upload {upload.id} {get_options(folder)}not authorized" raise AuthorizationError(description, response) else: description = f"Unable to copy upload {upload.uploadname} to {folder.name}" raise FossologyApiError(description, response)
def list_uploads(self, folder=None, group=None, recursive=True, page_size=20, page=1): """Get all uploads available to the registered user API Endpoint: GET /uploads :param folder: only list uploads from the given folder :param group: list uploads from a specific group (not only your own uploads) (default: None) :param recursive: wether to list uploads from children folders or not (default: True) :param page_size: limit the number of uploads per page (default: 20) :param page: the number of the page to fetch uploads from (default: 1) :type folder: Folder :type group: string :type recursive: boolean :type page_size: int :type page: int :return: a list of uploads :rtype: list of Upload :raises FossologyApiError: if the REST call failed :raises AuthorizationError: if the user can't access the group """ params = {} headers = {"limit": str(page_size), "page": str(page)} if group: headers["groupName"] = group if folder: params["folderId"] = folder.id if not recursive: params["recursive"] = "false" response = self.session.get(f"{self.api}/uploads", headers=headers, params=params) if response.status_code == 200: uploads_list = list() for upload in response.json(): uploads_list.append(Upload.from_json(upload)) logger.info( f"Retrieved page {page} of uploads, {response.headers.get('X-TOTAL-PAGES', 'Unknown')} pages are in total available" ) return uploads_list elif response.status_code == 403: description = ( f"Retrieving list of uploads {get_options(group, folder)}not authorized" ) raise AuthorizationError(description, response) else: description = "Unable to retrieve the list of uploads" raise FossologyApiError(description, response)
def fossology_token( url, username, password, token_name, token_scope=TokenScope.READ, token_expire=None ): """Generate an API token using username/password API endpoint: POST /tokens :Example: >>> from fossology import fossology_token # doctest: +SKIP >>> from fossology.obj import TokenScope # doctest: +SKIP >>> token = fossology_token("https://fossology.example.com", "Me", "MyPassword", "MyToken") # doctest: +SKIP :param url: the URL of the Fossology server :param username: name of the user the token will be generated for :param password: the password of the user :param name: the name of the token :param scope: the scope of the token (default: TokenScope.READ) :param expire: the expire date of the token, e.g. 2019-12-25 (default: max. 30 days) :type url: string :type username: string :type password: string :type name: string :type scope: TokenScope :type expire: string :return: the new token :rtype: string :raises AuthenticationError: if the username or password is incorrect :raises FossologyApiError: if another error occurs """ data = { "username": username, "password": password, "token_name": token_name, "token_scope": token_scope.value, } if token_expire: data["token_expire"] = token_expire else: now = date.today() data["token_expire"] = str(now + timedelta(days=30)) try: response = requests.post(url + "/api/v1/tokens", data=data) if response.status_code == 201: token = response.json()["Authorization"] return re.sub("Bearer ", "", token) elif response.status_code == 404: description = "Authentication error" raise AuthenticationError(description, response) else: description = "Error while generating new token" raise FossologyApiError(description, response) except requests.exceptions.ConnectionError as error: exit(f"Server {url} does not seem to be running or is unreachable: {error}")
def download_report(self, report_id: int, group: str = None) -> Tuple[str, str]: """Download a report API Endpoint: GET /report/{id} :Example: >>> from fossology.api import Fossology >>> >>> foss = Fossology(FOSS_URL, FOSS_TOKEN, username) >>> >>> # Generate a report for upload 1 >>> report_id = foss.generate_report(foss.detail_upload(1)) >>> report_content, report_name = foss.download_report(report_id) >>> with open(report_name, "w+") as report_file: >>> report_file.write(report_content) :param report_id: the id of the generated report :param group: the group name to choose while downloading a specific report (default: None) :type report_id: int :type group: string :return: the report content and the report name :rtype: Tuple[str, str] :raises FossologyApiError: if the REST call failed :raises AuthorizationError: if the user can't access the group :raises TryAgain: if the report generation timed out after 3 retries """ headers = dict() if group: headers["groupName"] = group response = self.session.get(f"{self.api}/report/{report_id}", headers=headers) if response.status_code == 200: content = response.headers["Content-Disposition"] report_name_pattern = '(^attachment; filename=")(.*)("$)' report_name = re.match(report_name_pattern, content).group(2) return response.text, report_name elif response.status_code == 403: description = ( f"Getting report {report_id} {get_options(group)}not authorized" ) raise AuthorizationError(description, response) elif response.status_code == 503: wait_time = response.headers["Retry-After"] logger.debug(f"Retry get report after {wait_time} seconds") time.sleep(int(wait_time)) raise TryAgain else: description = f"Download of report {report_id} failed" raise FossologyApiError(description, response)
def list_jobs(self, upload=None, page_size=100, page=1, all_pages=False): """Get all available jobs API Endpoint: GET /jobs The answer is limited to the first page of 20 results by default :param upload: list only jobs of the given upload (default: None) :param page_size: the maximum number of results per page :param page: the number of pages to be retrieved :param all_pages: get all jobs (default: False) :type upload: Upload :type page_size: int (default: 100) :type page: int (default: 1) :type all_pages: boolean :return: a tuple containing the list of jobs and the total number of pages :rtype: Tuple(list of Job, int) :raises FossologyApiError: if the REST call failed """ params = {} headers = {"limit": str(page_size)} if upload: params["upload"] = upload.id jobs_list = list() if all_pages: # will be reset after the total number of pages has been retrieved from the API x_total_pages = 2 else: x_total_pages = page while page <= x_total_pages: headers["page"] = str(page) response = self.session.get(f"{self.api}/jobs", params=params, headers=headers) if response.status_code == 200: for job in response.json(): jobs_list.append(Job.from_json(job)) x_total_pages = int(response.headers.get("X-TOTAL-PAGES", 0)) if not all_pages or x_total_pages == 0: logger.info( f"Retrieved page {page} of jobs, {x_total_pages} pages are in total available" ) return jobs_list, x_total_pages page += 1 else: description = f"Unable to retrieve the list of jobs from page {page}" raise FossologyApiError(description, response) logger.info(f"Retrieved all {x_total_pages} pages of jobs") return jobs_list, x_total_pages
def get_health(self) -> ApiInfo: """Get health from the server API endpoint: GET /health :return: the server health information :rtype: HealthInfo :raises FossologyApiError: if the REST call failed """ response = self.session.get(f"{self.api}/health") if response.status_code == 200: return HealthInfo.from_json(response.json()) else: description = "Error while getting health info" raise FossologyApiError(description, response)
def delete_folder(self, folder): """Delete a folder API Endpoint: DELETE /folders/{id} :param folder: the Folder to be deleted :type folder: Folder() object :raises FossologyApiError: if the REST call failed """ response = self.session.delete(f"{self.api}/folders/{folder.id}") if response.status_code == 202: logger.info(f"Folder {folder.id} has been scheduled for deletion") else: description = f"Unable to delete folder {folder.id}" raise FossologyApiError(description, response)
def detail_license( self, shortname, group=None ) -> Tuple[int, License, List[Obligation]]: """Get a license from the DB API Endpoint: GET /license/{shortname} :param shortname: Short name of the license :param group: the group this license belongs to (default: None) :type name: str :type group: int :return: the license id, the license data and the associated obligations :rtype: tuple(int, License, List[Obligation]) :raises FossologyApiError: if the REST call failed """ if fossology.versiontuple(self.version) < fossology.versiontuple("1.3.0"): description = ( f"Endpoint /license/{shortname} is not supported by your API version ", f"{self.version}", ) raise FossologyUnsupported(description) headers = dict() if group: headers["groupName"] = group response = self.session.get( f"{self.api}/license/{quote(shortname)}", headers=headers ) if response.status_code == 200: return License.from_json(response.json()) elif response.status_code == 404: description = f"License {shortname} not found" raise FossologyApiError(description, response) else: description = f"Error while getting license {shortname}" raise FossologyApiError(description, response)
def get_version(self): """Get API version from the server API endpoint: GET /version (deprecated since API version 1.3.3) :return: the API version string :rtype: string :raises FossologyApiError: if the REST call failed """ response = self.session.get(f"{self.api}/version") if response.status_code == 200: return response.json()["version"] else: description = "Error while getting API version" raise FossologyApiError(description, response)
def delete_user(self, user): """Delete a Fossology user. API Endpoint: DELETE /users/{id} :param user: the user to be deleted :type user: User :raises FossologyApiError: if the REST call failed """ response = self.session.delete(f"{self.api}/users/{user.id}") if response.status_code == 202: return else: description = f"Error while deleting user {user.name} ({user.id})" raise FossologyApiError(description, response)
def filesearch( self, filelist: List = [], group: str = None, ): """Search for files from hash sum API Endpoint: POST /filesearch The response does not generate Python objects yet, the plain JSON data is simply returned. :param filelist: the list of files (or containers) hashes to search for (default: []) :param group: the group name to choose while performing search (default: None) :type filelist: list :return: list of items corresponding to the search criteria :type group: string :rtype: JSON :raises FossologyApiError: if the REST call failed :raises AuthorizationError: if the user can't access the group """ if versiontuple(self.version) <= versiontuple("1.0.16"): description = f"Endpoint /filesearch is not supported by your Fossology API version {self.version}" raise FossologyUnsupported(description) headers = {} if group: headers["groupName"] = group response = self.session.post( f"{self.api}/filesearch", headers=headers, json=filelist ) if response.status_code == 200: all_files = [] for hash_file in response.json(): if hash_file.get("findings"): all_files.append(File.from_json(hash_file)) else: return "Unable to get a result with the given filesearch criteria" return all_files elif response.status_code == 403: description = f"Searching {get_options(group)}not authorized" raise AuthorizationError(description, response) else: description = "Unable to get a result with the given filesearch criteria" raise FossologyApiError(description, response)
def generate_report(self, upload: Upload, report_format: ReportFormat = None, group: str = None): """Generate a report for a given upload API Endpoint: GET /report :param upload: the upload which report will be generated :param format: the report format (default: ReportFormat.READMEOSS) :param group: the group name to choose while generating the report (default: None) :type upload: Upload :type format: ReportFormat :type group: string :return: the report id :rtype: int :raises FossologyApiError: if the REST call failed :raises AuthorizationError: if the user can't access the group """ headers = {"uploadId": str(upload.id)} if report_format: headers["reportFormat"] = report_format.value else: headers["reportFormat"] = "readmeoss" if group: headers["groupName"] = group response = self.session.get(f"{self.api}/report", headers=headers) if response.status_code == 201: report_id = re.search("[0-9]*$", response.json()["message"]) return report_id[0] elif response.status_code == 403: description = f"Generating report for upload {upload.id} {get_options(group)}not authorized" raise AuthorizationError(description, response) elif response.status_code == 503: wait_time = response.headers["Retry-After"] logger.debug(f"Retry generate report after {wait_time} seconds") time.sleep(int(wait_time)) raise TryAgain else: description = f"Report generation for upload {upload.uploadname} failed" raise FossologyApiError(description, response)
def update_license( self, shortname, fullname: str = "", text: str = "", url: str = "", risk: int = 2, ): """Update a license API Endpoint: PATCH /license/{shortname} :param shortName: the short name of the license to be updated :param fullName: the new fullName of the license (optional) :param text: the new text of the license (optional) :param url: the new url of the license (optional) :param risk: the new risk of the license (default: 2) :type shortName: str :type fullName: str :type text: str :type url: str :type risk: int :raises FossologyApiError: if the REST call failed """ headers = {"Content-Type": "application/json"} license_data = { "fullName": fullname, "text": text, "url": url, "risk": str(risk), } response = self.session.patch( f"{self.api}/license/{quote(shortname)}", data=json.dumps(license_data), headers=headers, ) if response.status_code == 200: logger.info(f"License {shortname} has been updated") return else: description = f"Unable to update license {shortname}" raise FossologyApiError(description, response)
def list_folders(self): """List all folders accessible to the authenticated user API Endpoint: GET /folders :return: a list of folders :rtype: list() :raises FossologyApiError: if the REST call failed """ response = self.session.get(f"{self.api}/folders") if response.status_code == 200: folders_list = list() response_list = response.json() for folder in response_list: sub_folder = Folder.from_json(folder) folders_list.append(sub_folder) return folders_list else: description = f"Unable to get a list of folders for {self.user.name}" raise FossologyApiError(description, response)
def detail_folder(self, folder_id): """Get details of folder. API Endpoint: GET /folders/{id} :param id: the ID of the folder to be analysed :type id: int :return: the requested folder :rtype: Folder() object :raises FossologyApiError: if the REST call failed """ response = self.session.get(f"{self.api}/folders/{folder_id}") if response.status_code == 200: detailled_folder = Folder.from_json(response.json()) for folder in self.folders: if folder.id == folder_id: self.folders.remove(folder) self.folders.append(detailled_folder) return detailled_folder else: description = f"Error while getting details for folder {folder_id}" raise FossologyApiError(description, response)
def create_group(self, name): """Create a group API Endpoint: POST /groups :param name: the name of the group :type name: str :raises FossologyApiError: if the REST call failed """ if fossology.versiontuple( self.version) < fossology.versiontuple("1.2.1"): description = f"Endpoint /groups is not supported by your Fossology API version {self.version}" raise FossologyUnsupported(description) headers = {"name": f"{name}"} response = self.session.post(f"{self.api}/groups", headers=headers) if response.status_code == 200: logger.info(f"Group '{name}' has been added") return else: description = f"Group {name} already exists, failed to create group or no group name provided" raise FossologyApiError(description, response)
def detail_user(self, user_id): """Get details of Fossology user. API Endpoint: GET /users/{id} :param id: the ID of the user :type id: int :return: the requested user's details :rtype: User :raises FossologyApiError: if the REST call failed """ response = self.session.get(f"{self.api}/users/{user_id}") if response.status_code == 200: user_agents = None user_details = response.json() if user_details.get("agents"): user_agents = Agents.from_json(user_details["agents"]) user = User.from_json(user_details) user.agents = user_agents return user else: description = f"Error while getting details for user {user_id}" raise FossologyApiError(description, response)
def detail_license(self, name) -> License: """Get a license from the DB API Endpoint: GET /license :param name: Short name of the license :rtype name: str :return: a list of groups :rtype: License() object :raises FossologyApiError: if the REST call failed """ if fossology.versiontuple( self.version) < fossology.versiontuple("1.1.3"): description = f"Endpoint /license is not supported by your Fossology API version {self.version}" raise FossologyUnsupported(description) headers = {"shortName": f"{name}"} response = self.session.get(f"{self.api}/license", headers=headers) if response.status_code == 200: return License.from_json(response.json()) else: description = f"Unable to get license {name}" raise FossologyApiError(description, response)
def upload_summary(self, upload, group=None): """Get clearing information about an upload API Endpoint: GET /uploads/{id}/summary :param upload: the upload to gather data from :param group: the group name to chose while accessing an upload (default: None) :type: Upload :type group: string :return: the upload summary data :rtype: Summary :raises FossologyApiError: if the REST call failed :raises AuthorizationError: if the user can't access the group """ headers = {} if group: headers["groupName"] = group response = self.session.get( f"{self.api}/uploads/{upload.id}/summary", headers=headers ) if response.status_code == 200: return Summary.from_json(response.json()) elif response.status_code == 403: description = f"Getting summary of upload {upload.id} {get_options(group)}not authorized" raise AuthorizationError(description, response) elif response.status_code == 503: logger.debug( f"Unpack agent for {upload.uploadname} (id={upload.id}) didn't start yet" ) time.sleep(3) raise TryAgain else: description = f"No summary for upload {upload.uploadname} (id={upload.id})" raise FossologyApiError(description, response)