|
Michal Koutný |
ccf7f1 |
# This work is licensed under the GNU GPLv2 or later.
|
|
Michal Koutný |
ccf7f1 |
# See the COPYING file in the top-level directory.
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
import base64
|
|
Michal Koutný |
ccf7f1 |
import json
|
|
Michal Koutný |
ccf7f1 |
import logging
|
|
Michal Koutný |
ccf7f1 |
import os
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
from ._backendbase import _BackendBase
|
|
Michal Koutný |
ccf7f1 |
from .exceptions import BugzillaError
|
|
Michal Koutný |
ccf7f1 |
from ._util import listify
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
log = logging.getLogger(__name__)
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def _update_key(indict, updict, key):
|
|
Michal Koutný |
ccf7f1 |
if key not in indict:
|
|
Michal Koutný |
ccf7f1 |
indict[key] = {}
|
|
Michal Koutný |
ccf7f1 |
indict[key].update(updict.get(key, {}))
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
class _BackendREST(_BackendBase):
|
|
Michal Koutný |
ccf7f1 |
"""
|
|
Michal Koutný |
ccf7f1 |
Internal interface for direct calls to bugzilla's REST API
|
|
Michal Koutný |
ccf7f1 |
"""
|
|
Michal Koutný |
ccf7f1 |
def __init__(self, url, bugzillasession):
|
|
Michal Koutný |
ccf7f1 |
_BackendBase.__init__(self, url, bugzillasession)
|
|
Michal Koutný |
ccf7f1 |
self._bugzillasession.set_rest_defaults()
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
#########################
|
|
Michal Koutný |
ccf7f1 |
# Internal REST helpers #
|
|
Michal Koutný |
ccf7f1 |
#########################
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def _handle_response(self, text):
|
|
Michal Koutný |
ccf7f1 |
try:
|
|
Michal Koutný |
ccf7f1 |
ret = dict(json.loads(text))
|
|
Michal Koutný |
ccf7f1 |
except Exception: # pragma: no cover
|
|
Michal Koutný |
ccf7f1 |
log.debug("Failed to parse REST response. Output is:\n%s", text)
|
|
Michal Koutný |
ccf7f1 |
raise
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
if ret.get("error", False):
|
|
Michal Koutný |
ccf7f1 |
raise BugzillaError(ret["message"], code=ret["code"])
|
|
Michal Koutný |
ccf7f1 |
return ret
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def _op(self, method, apiurl, paramdict=None):
|
|
Michal Koutný |
ccf7f1 |
fullurl = os.path.join(self._url, apiurl.lstrip("/"))
|
|
Michal Koutný |
ccf7f1 |
log.debug("Bugzilla REST %s %s params=%s", method, fullurl, paramdict)
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
data = None
|
|
Michal Koutný |
ccf7f1 |
authparams = self._bugzillasession.get_auth_params()
|
|
Michal Koutný |
ccf7f1 |
if method == "GET":
|
|
Michal Koutný |
ccf7f1 |
authparams.update(paramdict or {})
|
|
Michal Koutný |
ccf7f1 |
else:
|
|
Michal Koutný |
ccf7f1 |
data = json.dumps(paramdict or {})
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
response = self._bugzillasession.request(method, fullurl, data=data,
|
|
Michal Koutný |
ccf7f1 |
params=authparams)
|
|
Michal Koutný |
ccf7f1 |
return self._handle_response(response.text)
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def _get(self, *args, **kwargs):
|
|
Michal Koutný |
ccf7f1 |
return self._op("GET", *args, **kwargs)
|
|
Michal Koutný |
ccf7f1 |
def _put(self, *args, **kwargs):
|
|
Michal Koutný |
ccf7f1 |
return self._op("PUT", *args, **kwargs)
|
|
Michal Koutný |
ccf7f1 |
def _post(self, *args, **kwargs):
|
|
Michal Koutný |
ccf7f1 |
return self._op("POST", *args, **kwargs)
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
#######################
|
|
Michal Koutný |
ccf7f1 |
# API implementations #
|
|
Michal Koutný |
ccf7f1 |
#######################
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def get_xmlrpc_proxy(self):
|
|
Michal Koutný |
ccf7f1 |
raise BugzillaError("You are using the bugzilla REST API, "
|
|
Michal Koutný |
ccf7f1 |
"so raw XMLRPC access is not provided.")
|
|
Michal Koutný |
ccf7f1 |
def is_rest(self):
|
|
Michal Koutný |
ccf7f1 |
return True
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def bugzilla_version(self):
|
|
Michal Koutný |
ccf7f1 |
return self._get("/version")
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def bug_create(self, paramdict):
|
|
Michal Koutný |
ccf7f1 |
return self._post("/bug", paramdict)
|
|
Michal Koutný |
ccf7f1 |
def bug_fields(self, paramdict):
|
|
Michal Koutný |
ccf7f1 |
return self._get("/field/bug", paramdict)
|
|
Michal Koutný |
ccf7f1 |
def bug_get(self, bug_ids, aliases, paramdict):
|
|
Michal Koutný |
ccf7f1 |
data = paramdict.copy()
|
|
Michal Koutný |
ccf7f1 |
data["id"] = listify(bug_ids)
|
|
Michal Koutný |
ccf7f1 |
data["alias"] = listify(aliases)
|
|
Michal Koutný |
ccf7f1 |
ret = self._get("/bug", data)
|
|
Michal Koutný |
ccf7f1 |
return ret
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def bug_attachment_get(self, attachment_ids, paramdict):
|
|
Michal Koutný |
ccf7f1 |
# XMLRPC supported mutiple fetch at once, but not REST
|
|
Michal Koutný |
ccf7f1 |
ret = {}
|
|
Michal Koutný |
ccf7f1 |
for attid in listify(attachment_ids):
|
|
Michal Koutný |
ccf7f1 |
out = self._get("/bug/attachment/%s" % attid, paramdict)
|
|
Michal Koutný |
ccf7f1 |
_update_key(ret, out, "attachments")
|
|
Michal Koutný |
ccf7f1 |
_update_key(ret, out, "bugs")
|
|
Michal Koutný |
ccf7f1 |
return ret
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def bug_attachment_get_all(self, bug_ids, paramdict):
|
|
Michal Koutný |
ccf7f1 |
# XMLRPC supported mutiple fetch at once, but not REST
|
|
Michal Koutný |
ccf7f1 |
ret = {}
|
|
Michal Koutný |
ccf7f1 |
for bugid in listify(bug_ids):
|
|
Michal Koutný |
ccf7f1 |
out = self._get("/bug/%s/attachment" % bugid, paramdict)
|
|
Michal Koutný |
ccf7f1 |
_update_key(ret, out, "attachments")
|
|
Michal Koutný |
ccf7f1 |
_update_key(ret, out, "bugs")
|
|
Michal Koutný |
ccf7f1 |
return ret
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def bug_attachment_create(self, bug_ids, data, paramdict):
|
|
Michal Koutný |
ccf7f1 |
if data is not None and "data" not in paramdict:
|
|
Michal Koutný |
ccf7f1 |
paramdict["data"] = base64.b64encode(data).decode("utf-8")
|
|
Michal Koutný |
ccf7f1 |
paramdict["ids"] = listify(bug_ids)
|
|
Michal Koutný |
ccf7f1 |
return self._post("/bug/%s/attachment" % paramdict["ids"][0],
|
|
Michal Koutný |
ccf7f1 |
paramdict)
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def bug_attachment_update(self, attachment_ids, paramdict):
|
|
Michal Koutný |
ccf7f1 |
paramdict["ids"] = listify(attachment_ids)
|
|
Michal Koutný |
ccf7f1 |
return self._put("/bug/attachment/%s" % paramdict["ids"][0], paramdict)
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def bug_comments(self, bug_ids, paramdict):
|
|
Michal Koutný |
ccf7f1 |
# XMLRPC supported mutiple fetch at once, but not REST
|
|
Michal Koutný |
ccf7f1 |
ret = {}
|
|
Michal Koutný |
ccf7f1 |
for bugid in bug_ids:
|
|
Michal Koutný |
ccf7f1 |
out = self._get("/bug/%s/comment" % bugid, paramdict)
|
|
Michal Koutný |
ccf7f1 |
_update_key(ret, out, "bugs")
|
|
Michal Koutný |
ccf7f1 |
return ret
|
|
Michal Koutný |
ccf7f1 |
def bug_history(self, bug_ids, paramdict):
|
|
Michal Koutný |
ccf7f1 |
# XMLRPC supported mutiple fetch at once, but not REST
|
|
Michal Koutný |
ccf7f1 |
ret = {"bugs": []}
|
|
Michal Koutný |
ccf7f1 |
for bugid in bug_ids:
|
|
Michal Koutný |
ccf7f1 |
out = self._get("/bug/%s/history" % bugid, paramdict)
|
|
Michal Koutný |
ccf7f1 |
ret["bugs"].extend(out.get("bugs", []))
|
|
Michal Koutný |
ccf7f1 |
return ret
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def bug_search(self, paramdict):
|
|
Michal Koutný |
ccf7f1 |
return self._get("/bug", paramdict)
|
|
Michal Koutný |
ccf7f1 |
def bug_update(self, bug_ids, paramdict):
|
|
Michal Koutný |
ccf7f1 |
data = paramdict.copy()
|
|
Michal Koutný |
ccf7f1 |
data["ids"] = listify(bug_ids)
|
|
Michal Koutný |
ccf7f1 |
return self._put("/bug/%s" % data["ids"][0], data)
|
|
Michal Koutný |
ccf7f1 |
def bug_update_tags(self, bug_ids, paramdict):
|
|
Michal Koutný |
ccf7f1 |
raise BugzillaError("No REST API available for bug_update_tags")
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def component_create(self, paramdict):
|
|
Michal Koutný |
ccf7f1 |
return self._post("/component", paramdict)
|
|
Michal Koutný |
ccf7f1 |
def component_update(self, paramdict):
|
|
Michal Koutný |
ccf7f1 |
if "ids" in paramdict:
|
|
Michal Koutný |
ccf7f1 |
apiurl = str(listify(paramdict["ids"])[0]) # pragma: no cover
|
|
Michal Koutný |
ccf7f1 |
if "names" in paramdict:
|
|
Michal Koutný |
ccf7f1 |
apiurl = ("%(product)s/%(component)s" %
|
|
Michal Koutný |
ccf7f1 |
listify(paramdict["names"])[0])
|
|
Michal Koutný |
ccf7f1 |
return self._put("/component/%s" % apiurl, paramdict)
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def externalbugs_add(self, paramdict): # pragma: no cover
|
|
Michal Koutný |
ccf7f1 |
raise BugzillaError(
|
|
Michal Koutný |
ccf7f1 |
"No REST API available yet for externalbugs_add")
|
|
Michal Koutný |
ccf7f1 |
def externalbugs_remove(self, paramdict): # pragma: no cover
|
|
Michal Koutný |
ccf7f1 |
raise BugzillaError(
|
|
Michal Koutný |
ccf7f1 |
"No REST API available yet for externalbugs_remove")
|
|
Michal Koutný |
ccf7f1 |
def externalbugs_update(self, paramdict): # pragma: no cover
|
|
Michal Koutný |
ccf7f1 |
raise BugzillaError(
|
|
Michal Koutný |
ccf7f1 |
"No REST API available yet for externalbugs_update")
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def group_get(self, paramdict):
|
|
Michal Koutný |
ccf7f1 |
return self._get("/group", paramdict)
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def product_get(self, paramdict):
|
|
Michal Koutný |
ccf7f1 |
return self._get("/product/get", paramdict)
|
|
Michal Koutný |
ccf7f1 |
def product_get_accessible(self):
|
|
Michal Koutný |
ccf7f1 |
return self._get("/product_accessible")
|
|
Michal Koutný |
ccf7f1 |
def product_get_enterable(self):
|
|
Michal Koutný |
ccf7f1 |
return self._get("/product_enterable")
|
|
Michal Koutný |
ccf7f1 |
def product_get_selectable(self):
|
|
Michal Koutný |
ccf7f1 |
return self._get("/product_selectable")
|
|
Michal Koutný |
ccf7f1 |
|
|
Michal Koutný |
ccf7f1 |
def user_create(self, paramdict):
|
|
Michal Koutný |
ccf7f1 |
return self._post("/user", paramdict)
|
|
Michal Koutný |
ccf7f1 |
def user_get(self, paramdict):
|
|
Michal Koutný |
ccf7f1 |
return self._get("/user", paramdict)
|
|
Michal Koutný |
ccf7f1 |
def user_login(self, paramdict):
|
|
Michal Koutný |
ccf7f1 |
return self._get("/login", paramdict)
|
|
Michal Koutný |
ccf7f1 |
def user_logout(self):
|
|
Michal Koutný |
ccf7f1 |
return self._get("/logout")
|
|
Michal Koutný |
ccf7f1 |
def user_update(self, paramdict):
|
|
Michal Koutný |
ccf7f1 |
urlid = None
|
|
Michal Koutný |
ccf7f1 |
if "ids" in paramdict:
|
|
Michal Koutný |
ccf7f1 |
urlid = listify(paramdict["ids"])[0] # pragma: no cover
|
|
Michal Koutný |
ccf7f1 |
if "names" in paramdict:
|
|
Michal Koutný |
ccf7f1 |
urlid = listify(paramdict["names"])[0]
|
|
Michal Koutný |
ccf7f1 |
return self._put("/user/%s" % urlid, paramdict)
|