pyopenproject icon indicating copy to clipboard operation
pyopenproject copied to clipboard

Sub directory installations not fully supported

Open druggedhippo opened this issue 1 year ago • 0 comments

Issue

Subdirectory installations of OpenProject cause issues in some commands when the API generates links that contain relative URLs

https://www.openproject.org/docs/installation-and-operations/installation/docker/#2-location-subdirectory

Example

Host: www.host.com Subdirectory: op

Full base URL is http://www.host.com/op

Links to the API look like: https://www.host.com/op/api/v3/projects?filters=[]

But in the "links" and "href" returned by API calls the links are relative to the host: "href":"/op/api/v3/projects/147/work_packages/form"

When you then try to perform certain operations such as get_project_service().find_all() it attempts to use the links href to create the context for the request ( see find_list_command.py ) and causes URL failures when it gets to the request ( get_request.py )

requests.exceptions.HTTPError: 404 Client Error: Not Found for url: https://www.host.com/op/op/api/v3/projects?filters=%5B%5D&offset=2&pageSize=20

Because it is concatenating the original base URL with the relative href link instead of the host.

My fix

Here is my fix to get_request.py

import requests
from requests.auth import HTTPBasicAuth

from pyopenproject.api_connection.request import Request

from urllib.parse import urlparse

class GetRequest(Request):

    def __init__(self, connection, context):
        super().__init__(connection, context)

    def _execute_request(self):
        with requests.Session() as s:
            s.auth = HTTPBasicAuth(self.connection.api_user, self.connection.api_key)
            s.headers.update({"Content-Type": "application/hal+json"})
            conStr = ""
            # if the self.context doesn't start with /api, then assume it's a relative url and use the hostname
            if str(self.context).startswith("/api"):
                conStr = self.connection.url_base + self.context
            else:
                o = urlparse(self.connection.url_base)
                conStr = o.scheme + "://" + o.netloc + self.context
            response = s.get(conStr)
        return response

druggedhippo avatar Jul 10 '23 06:07 druggedhippo