]> git.ipfire.org Git - ipfire.org.git/blame - src/backend/bugzilla.py
lists: Implement some basic code to talk to Mailman
[ipfire.org.git] / src / backend / bugzilla.py
CommitLineData
26ccb61a
MT
1#!/usr/bin/python3
2
3import json
4import urllib.parse
5
d0502fb3 6from . import httpclient
26ccb61a
MT
7from . import misc
8from .decorators import *
9
10class BugzillaError(Exception):
11 pass
12
13class Bugzilla(misc.Object):
14 def init(self, api_key=None):
15 if api_key is None:
16 api_key = self.settings.get("bugzilla-api-key")
17
18 # Store the API key
19 self.api_key = api_key
20
21 @property
22 def url(self):
23 """
24 Returns the base URL of a Bugzilla instance
25 """
26 return self.settings.get("bugzilla-url")
27
28 def make_url(self, *args, **kwargs):
29 """
30 Composes a URL based on the base URL
31 """
32 url = urllib.parse.urljoin(self.url, *args)
33
34 # Append any query arguments
35 if kwargs:
36 url = "%s?%s" % (url, urllib.parse.urlencode(kwargs))
37
38 return url
39
40 async def _request(self, method, url, data=None):
41 if data is None:
42 data = {}
43
44 # Headers
45 headers = {
46 # Authenticate all requests
47 "X-BUGZILLA-API-KEY" : self.api_key,
48 }
49
50 # Make the URL
51 url = self.make_url(url)
52
53 # Fallback authentication because some API endpoints
54 # do not accept the API key in the header
55 data |= { "api_key" : self.api_key }
56
57 # Encode body
58 body = None
59
60 # For GET requests, append query arguments
61 if method == "GET":
62 if data:
63 url = "%s?%s" % (url, urllib.parse.urlencode(data))
64
65 # For POST/PUT encode all arguments as JSON
66 elif method in ("POST", "PUT"):
67 headers |= {
68 "Content-Type" : "application/json",
69 }
70
71 body = json.dumps(data)
72
73 # Send the request and wait for a response
74 res = await self.backend.http_client.fetch(
75 url, method=method, headers=headers, body=body)
76
77 # Decode JSON response
78 body = json.loads(res.body)
79
80 # Check for any errors
81 if "error" in body:
82 # Fetch code and message
83 code, message = body.get("code"), body.get("message")
84
85 # Handle any so far unhandled errors
86 raise BugzillaError(message)
87
88 # Return an empty response
89 return body
90
91 async def get_user(self, uid):
92 """
93 Fetches a user from Bugzilla
94 """
d0502fb3
MT
95 try:
96 response = await self._request("GET", "/rest/user/%s" % uid)
97
98 # Return nothing if the user could not be found
99 except httpclient.HTTPError as e:
100 if e.code == 404:
101 return
102
103 raise e
26ccb61a
MT
104
105 # Return the user object
106 for data in response.get("users"):
107 return User(self.backend, data)
108
109
110
111class User(misc.Object):
112 def init(self, data):
113 self.data = data
114
115 @property
116 def id(self):
117 return self.data.get("id")
118
119 async def _update(self, **kwargs):
120 # Send the request
121 await self.backend.bugzilla._request("PUT", "/rest/user/%s" % self.id, **kwargs)
122
123 # XXX apply changes to the User object?
124
125 async def disable(self, text=None):
126 """
127 Disables this user
128 """
129 if not text:
130 text = "DISABLED"
131
132 # Update the user
133 await self._update(data={
134 "login_denied_text" : text,
135 })