Esempio n. 1
0
    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)
Esempio n. 2
0
    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)
Esempio n. 3
0
    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)
Esempio n. 4
0
    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)
Esempio n. 5
0
    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)
Esempio n. 6
0
    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)
Esempio n. 7
0
    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)
Esempio n. 8
0
    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)
Esempio n. 9
0
    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)
Esempio n. 10
0
    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)
Esempio n. 11
0
    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)
Esempio n. 12
0
    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)
Esempio n. 13
0
    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)
Esempio n. 14
0
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}")
Esempio n. 15
0
    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)
Esempio n. 16
0
    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
Esempio n. 17
0
    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)
Esempio n. 18
0
    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)
Esempio n. 19
0
    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)
Esempio n. 20
0
    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)
Esempio n. 21
0
    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)
Esempio n. 22
0
    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)
Esempio n. 23
0
    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)
Esempio n. 24
0
    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)
Esempio n. 25
0
    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)
Esempio n. 26
0
    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)
Esempio n. 27
0
    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)
Esempio n. 28
0
    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)
Esempio n. 29
0
    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)
Esempio n. 30
0
    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)