5
5
6
6
from aiohttp import ClientResponseError , ClientResponse
7
7
from discord import Member , DMChannel
8
+ from discord .ext import commands
8
9
9
10
from core .models import Bot , UserClient
10
11
11
12
12
13
class ApiClient :
14
+ """
15
+ This class represents the general request class for all type of clients.
16
+
17
+ Parameters
18
+ ----------
19
+ bot : Bot
20
+ The Modmail bot.
21
+
22
+ Attributes
23
+ ----------
24
+ bot : Bot
25
+ The Modmail bot.
26
+ session : ClientSession
27
+ The bot's current running `ClientSession`.
28
+ headers : Dict[str, str]
29
+ The HTTP headers that will be sent along with the requiest.
30
+ """
31
+
13
32
def __init__ (self , bot : Bot ):
14
33
self .bot = bot
15
34
self .session = bot .session
@@ -21,6 +40,31 @@ async def request(self, url: str,
21
40
return_response : bool = False ,
22
41
headers : dict = None ) -> Union [ClientResponse ,
23
42
dict , str ]:
43
+ """
44
+ Makes a HTTP request.
45
+
46
+ Parameters
47
+ ----------
48
+ url : str
49
+ The destination URL of the request.
50
+ method : str
51
+ The HTTP method (POST, GET, PUT, DELETE, FETCH, etc.).
52
+ payload : Dict[str, Any]
53
+ The json payload to be sent along the request.
54
+ return_response : bool
55
+ Whether the `ClientResponse` object should be returned.
56
+ headers : Dict[str, str]
57
+ Additional headers to `headers`.
58
+
59
+ Returns
60
+ -------
61
+ ClientResponse or Dict[str, Any] or List[Any] or str
62
+ `ClientResponse` if `return_response` is `True`.
63
+ `dict` if the returned data is a json object.
64
+ `list` if the returned data is a json list.
65
+ `str` if the returned data is not a valid json data,
66
+ the raw response.
67
+ """
24
68
if headers is not None :
25
69
headers .update (self .headers )
26
70
else :
@@ -35,16 +79,74 @@ async def request(self, url: str,
35
79
return await resp .text ()
36
80
37
81
def filter_valid (self , data ):
82
+ """
83
+ Filters configuration keys that are accepted.
84
+
85
+ Parameters
86
+ ----------
87
+ data : Dict[str, Any]
88
+ The data that needs to be cleaned.
89
+
90
+ Returns
91
+ -------
92
+ Dict[str, Any]
93
+ Filtered `data` to keep only the accepted pairs.
94
+ """
38
95
valid_keys = self .bot .config .valid_keys .difference (
39
96
self .bot .config .protected_keys
40
97
)
41
98
return {k : v for k , v in data .items () if k in valid_keys }
42
99
43
100
44
- class Github (ApiClient ):
101
+ class GitHub (ApiClient ):
102
+ """
103
+ The client for interacting with GitHub API.
104
+
105
+ Parameters
106
+ ----------
107
+ bot : Bot
108
+ The Modmail bot.
109
+ access_token : str, optional
110
+ GitHub's access token.
111
+ username : str, optional
112
+ GitHub username.
113
+ avatar_url : str, optional
114
+ URL to the avatar in GitHub.
115
+ url : str, optional
116
+ URL to the GitHub profile.
117
+
118
+ Attributes
119
+ ----------
120
+ bot : Bot
121
+ The Modmail bot.
122
+ access_token : str
123
+ GitHub's access token.
124
+ username : str
125
+ GitHub username.
126
+ avatar_url : str
127
+ URL to the avatar in GitHub.
128
+ url : str
129
+ URL to the GitHub profile.
130
+
131
+ Class Attributes
132
+ ----------------
133
+ BASE : str
134
+ GitHub API base URL.
135
+ REPO : str
136
+ Modmail repo URL for GitHub API.
137
+ HEAD : str
138
+ Modmail HEAD URL for GitHub API.
139
+ MERGE_URL : str
140
+ URL for merging upstream to master.
141
+ FORK_URL : str
142
+ URL to fork Modmail.
143
+ STAR_URL : str
144
+ URL to star Modmail.
145
+ """
146
+
45
147
BASE = 'https://api.github.com'
46
148
REPO = BASE + '/repos/kyb3r/modmail'
47
- head = REPO + '/git/refs/heads/master'
149
+ HEAD = REPO + '/git/refs/heads/master'
48
150
MERGE_URL = BASE + '/repos/{username}/modmail/merges'
49
151
FORK_URL = REPO + '/forks'
50
152
STAR_URL = BASE + '/user/starred/kyb3r/modmail'
@@ -56,15 +158,30 @@ def __init__(self, bot: Bot,
56
158
super ().__init__ (bot )
57
159
self .access_token = access_token
58
160
self .username = username
59
- self .id : str = kwargs .pop ('id' , '' )
60
161
self .avatar_url : str = kwargs .pop ('avatar_url' , '' )
61
162
self .url : str = kwargs .pop ('url' , '' )
62
163
if self .access_token :
63
164
self .headers = {'Authorization' : 'token ' + str (access_token )}
64
165
65
166
async def update_repository (self , sha : str = None ) -> Optional [dict ]:
167
+ """
168
+ Update the repository from Modmail main repo.
169
+
170
+ Parameters
171
+ ----------
172
+ sha : Optional[str], optional
173
+ The commit SHA to update the repository.
174
+
175
+ Returns
176
+ -------
177
+ Optional[dict]
178
+ If the response is a dict.
179
+ """
180
+ if not self .username :
181
+ raise commands .CommandInvokeError ("Username not found." )
182
+
66
183
if sha is None :
67
- resp : dict = await self .request (self .head )
184
+ resp : dict = await self .request (self .HEAD )
68
185
sha = resp ['object' ]['sha' ]
69
186
70
187
payload = {
@@ -80,25 +197,52 @@ async def update_repository(self, sha: str = None) -> Optional[dict]:
80
197
return resp
81
198
82
199
async def fork_repository (self ) -> None :
200
+ """
201
+ Forks Modmail's repository.
202
+ """
83
203
await self .request (self .FORK_URL , method = 'POST' )
84
204
85
205
async def has_starred (self ) -> bool :
206
+ """
207
+ Checks if shared Modmail.
208
+
209
+ Returns
210
+ -------
211
+ bool
212
+ `True`, if Modmail was starred.
213
+ Otherwise `False`.
214
+ """
86
215
resp = await self .request (self .STAR_URL , return_response = True )
87
216
return resp .status == 204
88
217
89
218
async def star_repository (self ) -> None :
219
+ """
220
+ Stars Modmail's repository.
221
+ """
90
222
await self .request (self .STAR_URL , method = 'PUT' ,
91
223
headers = {'Content-Length' : '0' })
92
224
93
225
@classmethod
94
- async def login (cls , bot ) -> 'Github' :
226
+ async def login (cls , bot : Bot ) -> 'GitHub' :
227
+ """
228
+ Logs in to GitHub with configuration variable information.
229
+
230
+ Parameters
231
+ ----------
232
+ bot : Bot
233
+ The Modmail bot.
234
+
235
+ Returns
236
+ -------
237
+ GitHub
238
+ The newly created `GitHub` object.
239
+ """
95
240
self = cls (bot , bot .config .get ('github_access_token' ), )
96
241
resp : dict = await self .request ('https://api.github.com/user' )
97
242
self .username : str = resp ['login' ]
98
243
self .avatar_url : str = resp ['avatar_url' ]
99
244
self .url : str = resp ['html_url' ]
100
- self .id : str = str (resp ['id' ])
101
- print (f'Logged in to: { self .username } - { self .id } ' )
245
+ print (f'Logged in to: { self .username } ' )
102
246
return self
103
247
104
248
@@ -361,7 +505,7 @@ async def post_log(self, channel_id, data):
361
505
)
362
506
363
507
async def update_repository (self ):
364
- user = await Github .login (self .bot )
508
+ user = await GitHub .login (self .bot )
365
509
data = await user .update_repository ()
366
510
return {
367
511
'data' : data ,
@@ -373,7 +517,7 @@ async def update_repository(self):
373
517
}
374
518
375
519
async def get_user_info (self ):
376
- user = await Github .login (self .bot )
520
+ user = await GitHub .login (self .bot )
377
521
return {
378
522
'user' : {
379
523
'username' : user .username ,
0 commit comments