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