diff options
Diffstat (limited to 'mastodon/accounts.py')
-rw-r--r-- | mastodon/accounts.py | 395 |
1 files changed, 394 insertions, 1 deletions
diff --git a/mastodon/accounts.py b/mastodon/accounts.py index 5ecdf93..219edac 100644 --- a/mastodon/accounts.py +++ b/mastodon/accounts.py | |||
@@ -1,5 +1,10 @@ | |||
1 | # accounts.py - account related endpoints | ||
2 | |||
3 | import collections | ||
4 | |||
5 | from .versions import _DICT_VERSION_ACCOUNT, _DICT_VERSION_STATUS, _DICT_VERSION_RELATIONSHIP, _DICT_VERSION_LIST, _DICT_VERSION_FAMILIAR_FOLLOWERS, _DICT_VERSION_HASHTAG | ||
1 | from .defaults import _DEFAULT_SCOPES, _SCOPE_SETS | 6 | from .defaults import _DEFAULT_SCOPES, _SCOPE_SETS |
2 | from .error import MastodonIllegalArgumentError, MastodonAPIError | 7 | from .errors import MastodonIllegalArgumentError, MastodonAPIError |
3 | from .utility import api_version | 8 | from .utility import api_version |
4 | 9 | ||
5 | from .internals import Mastodon as Internals | 10 | from .internals import Mastodon as Internals |
@@ -105,3 +110,391 @@ class Mastodon(Internals): | |||
105 | Only available to the app that the user originally signed up with. | 110 | Only available to the app that the user originally signed up with. |
106 | """ | 111 | """ |
107 | self.__api_request('POST', '/api/v1/emails/confirmations') | 112 | self.__api_request('POST', '/api/v1/emails/confirmations') |
113 | |||
114 | ### | ||
115 | # Reading data: Accounts | ||
116 | ### | ||
117 | @api_version("1.0.0", "1.0.0", _DICT_VERSION_ACCOUNT) | ||
118 | def account(self, id): | ||
119 | """ | ||
120 | Fetch account information by user `id`. | ||
121 | |||
122 | Does not require authentication for publicly visible accounts. | ||
123 | |||
124 | Returns a :ref:`account dict <account dict>`. | ||
125 | """ | ||
126 | id = self.__unpack_id(id) | ||
127 | url = '/api/v1/accounts/{0}'.format(str(id)) | ||
128 | return self.__api_request('GET', url) | ||
129 | |||
130 | @api_version("1.0.0", "2.1.0", _DICT_VERSION_ACCOUNT) | ||
131 | def account_verify_credentials(self): | ||
132 | """ | ||
133 | Fetch logged-in user's account information. | ||
134 | |||
135 | Returns a :ref:`account dict <account dict>` (Starting from 2.1.0, with an additional "source" field). | ||
136 | """ | ||
137 | return self.__api_request('GET', '/api/v1/accounts/verify_credentials') | ||
138 | |||
139 | @api_version("1.0.0", "2.1.0", _DICT_VERSION_ACCOUNT) | ||
140 | def me(self): | ||
141 | """ | ||
142 | Get this user's account. Synonym for `account_verify_credentials()`, does exactly | ||
143 | the same thing, just exists becase `account_verify_credentials()` has a confusing | ||
144 | name. | ||
145 | """ | ||
146 | return self.account_verify_credentials() | ||
147 | |||
148 | @api_version("1.0.0", "2.8.0", _DICT_VERSION_STATUS) | ||
149 | def account_statuses(self, id, only_media=False, pinned=False, exclude_replies=False, exclude_reblogs=False, tagged=None, max_id=None, min_id=None, since_id=None, limit=None): | ||
150 | """ | ||
151 | Fetch statuses by user `id`. Same options as :ref:`timeline() <timeline()>` are permitted. | ||
152 | Returned toots are from the perspective of the logged-in user, i.e. | ||
153 | all statuses visible to the logged-in user (including DMs) are | ||
154 | included. | ||
155 | |||
156 | If `only_media` is set, return only statuses with media attachments. | ||
157 | If `pinned` is set, return only statuses that have been pinned. Note that | ||
158 | as of Mastodon 2.1.0, this only works properly for instance-local users. | ||
159 | If `exclude_replies` is set, filter out all statuses that are replies. | ||
160 | If `exclude_reblogs` is set, filter out all statuses that are reblogs. | ||
161 | If `tagged` is set, return only statuses that are tagged with `tagged`. Only a single tag without a '#' is valid. | ||
162 | |||
163 | Does not require authentication for Mastodon versions after 2.7.0 (returns | ||
164 | publicly visible statuses in that case), for publicly visible accounts. | ||
165 | |||
166 | Returns a list of :ref:`status dicts <status dicts>`. | ||
167 | """ | ||
168 | id = self.__unpack_id(id) | ||
169 | if max_id is not None: | ||
170 | max_id = self.__unpack_id(max_id, dateconv=True) | ||
171 | |||
172 | if min_id is not None: | ||
173 | min_id = self.__unpack_id(min_id, dateconv=True) | ||
174 | |||
175 | if since_id is not None: | ||
176 | since_id = self.__unpack_id(since_id, dateconv=True) | ||
177 | |||
178 | params = self.__generate_params(locals(), ['id']) | ||
179 | if not pinned: | ||
180 | del params["pinned"] | ||
181 | if not only_media: | ||
182 | del params["only_media"] | ||
183 | if not exclude_replies: | ||
184 | del params["exclude_replies"] | ||
185 | if not exclude_reblogs: | ||
186 | del params["exclude_reblogs"] | ||
187 | |||
188 | url = '/api/v1/accounts/{0}/statuses'.format(str(id)) | ||
189 | return self.__api_request('GET', url, params) | ||
190 | |||
191 | @api_version("1.0.0", "2.6.0", _DICT_VERSION_ACCOUNT) | ||
192 | def account_following(self, id, max_id=None, min_id=None, since_id=None, limit=None): | ||
193 | """ | ||
194 | Fetch users the given user is following. | ||
195 | |||
196 | Returns a list of :ref:`account dicts <account dicts>`. | ||
197 | """ | ||
198 | id = self.__unpack_id(id) | ||
199 | if max_id is not None: | ||
200 | max_id = self.__unpack_id(max_id, dateconv=True) | ||
201 | |||
202 | if min_id is not None: | ||
203 | min_id = self.__unpack_id(min_id, dateconv=True) | ||
204 | |||
205 | if since_id is not None: | ||
206 | since_id = self.__unpack_id(since_id, dateconv=True) | ||
207 | |||
208 | params = self.__generate_params(locals(), ['id']) | ||
209 | url = '/api/v1/accounts/{0}/following'.format(str(id)) | ||
210 | return self.__api_request('GET', url, params) | ||
211 | |||
212 | @api_version("1.0.0", "2.6.0", _DICT_VERSION_ACCOUNT) | ||
213 | def account_followers(self, id, max_id=None, min_id=None, since_id=None, limit=None): | ||
214 | """ | ||
215 | Fetch users the given user is followed by. | ||
216 | |||
217 | Returns a list of :ref:`account dicts <account dicts>`. | ||
218 | """ | ||
219 | id = self.__unpack_id(id) | ||
220 | if max_id is not None: | ||
221 | max_id = self.__unpack_id(max_id, dateconv=True) | ||
222 | |||
223 | if min_id is not None: | ||
224 | min_id = self.__unpack_id(min_id, dateconv=True) | ||
225 | |||
226 | if since_id is not None: | ||
227 | since_id = self.__unpack_id(since_id, dateconv=True) | ||
228 | |||
229 | params = self.__generate_params(locals(), ['id']) | ||
230 | url = '/api/v1/accounts/{0}/followers'.format(str(id)) | ||
231 | return self.__api_request('GET', url, params) | ||
232 | |||
233 | @api_version("1.0.0", "1.4.0", _DICT_VERSION_RELATIONSHIP) | ||
234 | def account_relationships(self, id): | ||
235 | """ | ||
236 | Fetch relationship (following, followed_by, blocking, follow requested) of | ||
237 | the logged in user to a given account. `id` can be a list. | ||
238 | |||
239 | Returns a list of :ref:`relationship dicts <relationship dicts>`. | ||
240 | """ | ||
241 | id = self.__unpack_id(id) | ||
242 | params = self.__generate_params(locals()) | ||
243 | return self.__api_request('GET', '/api/v1/accounts/relationships', | ||
244 | params) | ||
245 | |||
246 | @api_version("1.0.0", "2.3.0", _DICT_VERSION_ACCOUNT) | ||
247 | def account_search(self, q, limit=None, following=False): | ||
248 | """ | ||
249 | Fetch matching accounts. Will lookup an account remotely if the search term is | ||
250 | in the username@domain format and not yet in the database. Set `following` to | ||
251 | True to limit the search to users the logged-in user follows. | ||
252 | |||
253 | Returns a list of :ref:`account dicts <account dicts>`. | ||
254 | """ | ||
255 | params = self.__generate_params(locals()) | ||
256 | |||
257 | if params["following"] == False: | ||
258 | del params["following"] | ||
259 | |||
260 | return self.__api_request('GET', '/api/v1/accounts/search', params) | ||
261 | |||
262 | @api_version("2.1.0", "2.1.0", _DICT_VERSION_LIST) | ||
263 | def account_lists(self, id): | ||
264 | """ | ||
265 | Get all of the logged-in user's lists which the specified user is | ||
266 | a member of. | ||
267 | |||
268 | Returns a list of :ref:`list dicts <list dicts>`. | ||
269 | """ | ||
270 | id = self.__unpack_id(id) | ||
271 | params = self.__generate_params(locals(), ['id']) | ||
272 | url = '/api/v1/accounts/{0}/lists'.format(str(id)) | ||
273 | return self.__api_request('GET', url, params) | ||
274 | |||
275 | @api_version("3.4.0", "3.4.0", _DICT_VERSION_ACCOUNT) | ||
276 | def account_lookup(self, acct): | ||
277 | """ | ||
278 | Look up an account from user@instance form (@instance allowed but not required for | ||
279 | local accounts). Will only return accounts that the instance already knows about, | ||
280 | and not do any webfinger requests. Use `account_search` if you need to resolve users | ||
281 | through webfinger from remote. | ||
282 | |||
283 | Returns an :ref:`account dict <account dict>`. | ||
284 | """ | ||
285 | return self.__api_request('GET', '/api/v1/accounts/lookup', self.__generate_params(locals())) | ||
286 | |||
287 | @api_version("3.5.0", "3.5.0", _DICT_VERSION_FAMILIAR_FOLLOWERS) | ||
288 | def account_familiar_followers(self, id): | ||
289 | """ | ||
290 | Find followers for the account given by id (can be a list) that also follow the | ||
291 | logged in account. | ||
292 | |||
293 | Returns a list of :ref:`familiar follower dicts <familiar follower dicts>` | ||
294 | """ | ||
295 | if not isinstance(id, list): | ||
296 | id = [id] | ||
297 | for i in range(len(id)): | ||
298 | id[i] = self.__unpack_id(id[i]) | ||
299 | return self.__api_request('GET', '/api/v1/accounts/familiar_followers', {'id': id}, use_json=True) | ||
300 | |||
301 | ### | ||
302 | # Writing data: Accounts | ||
303 | ### | ||
304 | @api_version("1.0.0", "3.3.0", _DICT_VERSION_RELATIONSHIP) | ||
305 | def account_follow(self, id, reblogs=True, notify=False): | ||
306 | """ | ||
307 | Follow a user. | ||
308 | |||
309 | Set `reblogs` to False to hide boosts by the followed user. | ||
310 | Set `notify` to True to get a notification every time the followed user posts. | ||
311 | |||
312 | Returns a :ref:`relationship dict <relationship dict>` containing the updated relationship to the user. | ||
313 | """ | ||
314 | id = self.__unpack_id(id) | ||
315 | params = self.__generate_params(locals(), ["id"]) | ||
316 | |||
317 | if params["reblogs"] is None: | ||
318 | del params["reblogs"] | ||
319 | |||
320 | url = '/api/v1/accounts/{0}/follow'.format(str(id)) | ||
321 | return self.__api_request('POST', url, params) | ||
322 | |||
323 | @api_version("1.0.0", "2.1.0", _DICT_VERSION_ACCOUNT) | ||
324 | def follows(self, uri): | ||
325 | """ | ||
326 | Follow a remote user by uri (username@domain). | ||
327 | |||
328 | Returns a :ref:`account dict <account dict>`. | ||
329 | """ | ||
330 | params = self.__generate_params(locals()) | ||
331 | return self.__api_request('POST', '/api/v1/follows', params) | ||
332 | |||
333 | @api_version("1.0.0", "1.4.0", _DICT_VERSION_RELATIONSHIP) | ||
334 | def account_unfollow(self, id): | ||
335 | """ | ||
336 | Unfollow a user. | ||
337 | |||
338 | Returns a :ref:`relationship dict <relationship dict>` containing the updated relationship to the user. | ||
339 | """ | ||
340 | id = self.__unpack_id(id) | ||
341 | return self.__api_request('POST', '/api/v1/accounts/{0}/unfollow'.format(str(id))) | ||
342 | |||
343 | @api_version("3.5.0", "3.5.0", _DICT_VERSION_RELATIONSHIP) | ||
344 | def account_remove_from_followers(self, id): | ||
345 | """ | ||
346 | Remove a user from the logged in users followers (i.e. make them unfollow the logged in | ||
347 | user / "softblock" them). | ||
348 | |||
349 | Returns a :ref:`relationship dict <relationship dict>` reflecting the updated following status. | ||
350 | """ | ||
351 | id = self.__unpack_id(id) | ||
352 | return self.__api_request('POST', '/api/v1/accounts/{0}/remove_from_followers'.format(str(id))) | ||
353 | |||
354 | |||
355 | @api_version("1.0.0", "1.4.0", _DICT_VERSION_RELATIONSHIP) | ||
356 | def account_block(self, id): | ||
357 | """ | ||
358 | Block a user. | ||
359 | |||
360 | Returns a :ref:`relationship dict <relationship dict>` containing the updated relationship to the user. | ||
361 | """ | ||
362 | id = self.__unpack_id(id) | ||
363 | url = '/api/v1/accounts/{0}/block'.format(str(id)) | ||
364 | return self.__api_request('POST', url) | ||
365 | |||
366 | @api_version("1.0.0", "1.4.0", _DICT_VERSION_RELATIONSHIP) | ||
367 | def account_unblock(self, id): | ||
368 | """ | ||
369 | Unblock a user. | ||
370 | |||
371 | Returns a :ref:`relationship dict <relationship dict>` containing the updated relationship to the user. | ||
372 | """ | ||
373 | id = self.__unpack_id(id) | ||
374 | url = '/api/v1/accounts/{0}/unblock'.format(str(id)) | ||
375 | return self.__api_request('POST', url) | ||
376 | |||
377 | @api_version("1.1.0", "2.4.3", _DICT_VERSION_RELATIONSHIP) | ||
378 | def account_mute(self, id, notifications=True, duration=None): | ||
379 | """ | ||
380 | Mute a user. | ||
381 | |||
382 | Set `notifications` to False to receive notifications even though the user is | ||
383 | muted from timelines. Pass a `duration` in seconds to have Mastodon automatically | ||
384 | lift the mute after that many seconds. | ||
385 | |||
386 | Returns a :ref:`relationship dict <relationship dict>` containing the updated relationship to the user. | ||
387 | """ | ||
388 | id = self.__unpack_id(id) | ||
389 | params = self.__generate_params(locals(), ['id']) | ||
390 | url = '/api/v1/accounts/{0}/mute'.format(str(id)) | ||
391 | return self.__api_request('POST', url, params) | ||
392 | |||
393 | @api_version("1.1.0", "1.4.0", _DICT_VERSION_RELATIONSHIP) | ||
394 | def account_unmute(self, id): | ||
395 | """ | ||
396 | Unmute a user. | ||
397 | |||
398 | Returns a :ref:`relationship dict <relationship dict>` containing the updated relationship to the user. | ||
399 | """ | ||
400 | id = self.__unpack_id(id) | ||
401 | url = '/api/v1/accounts/{0}/unmute'.format(str(id)) | ||
402 | return self.__api_request('POST', url) | ||
403 | |||
404 | @api_version("1.1.1", "3.1.0", _DICT_VERSION_ACCOUNT) | ||
405 | def account_update_credentials(self, display_name=None, note=None, | ||
406 | avatar=None, avatar_mime_type=None, | ||
407 | header=None, header_mime_type=None, | ||
408 | locked=None, bot=None, | ||
409 | discoverable=None, fields=None): | ||
410 | """ | ||
411 | Update the profile for the currently logged-in user. | ||
412 | |||
413 | `note` is the user's bio. | ||
414 | |||
415 | `avatar` and 'header' are images. As with media uploads, it is possible to either | ||
416 | pass image data and a mime type, or a filename of an image file, for either. | ||
417 | |||
418 | `locked` specifies whether the user needs to manually approve follow requests. | ||
419 | |||
420 | `bot` specifies whether the user should be set to a bot. | ||
421 | |||
422 | `discoverable` specifies whether the user should appear in the user directory. | ||
423 | |||
424 | `fields` can be a list of up to four name-value pairs (specified as tuples) to | ||
425 | appear as semi-structured information in the user's profile. | ||
426 | |||
427 | Returns the updated `account dict` of the logged-in user. | ||
428 | """ | ||
429 | params_initial = collections.OrderedDict(locals()) | ||
430 | |||
431 | # Convert fields | ||
432 | if fields is not None: | ||
433 | if len(fields) > 4: | ||
434 | raise MastodonIllegalArgumentError( | ||
435 | 'A maximum of four fields are allowed.') | ||
436 | |||
437 | fields_attributes = [] | ||
438 | for idx, (field_name, field_value) in enumerate(fields): | ||
439 | params_initial['fields_attributes[' + | ||
440 | str(idx) + '][name]'] = field_name | ||
441 | params_initial['fields_attributes[' + | ||
442 | str(idx) + '][value]'] = field_value | ||
443 | |||
444 | # Clean up params | ||
445 | for param in ["avatar", "avatar_mime_type", "header", "header_mime_type", "fields"]: | ||
446 | if param in params_initial: | ||
447 | del params_initial[param] | ||
448 | |||
449 | # Create file info | ||
450 | files = {} | ||
451 | if avatar is not None: | ||
452 | files["avatar"] = self.__load_media_file(avatar, avatar_mime_type) | ||
453 | if header is not None: | ||
454 | files["header"] = self.__load_media_file(header, header_mime_type) | ||
455 | |||
456 | params = self.__generate_params(params_initial) | ||
457 | return self.__api_request('PATCH', '/api/v1/accounts/update_credentials', params, files=files) | ||
458 | |||
459 | @api_version("2.5.0", "2.5.0", _DICT_VERSION_RELATIONSHIP) | ||
460 | def account_pin(self, id): | ||
461 | """ | ||
462 | Pin / endorse a user. | ||
463 | |||
464 | Returns a :ref:`relationship dict <relationship dict>` containing the updated relationship to the user. | ||
465 | """ | ||
466 | id = self.__unpack_id(id) | ||
467 | url = '/api/v1/accounts/{0}/pin'.format(str(id)) | ||
468 | return self.__api_request('POST', url) | ||
469 | |||
470 | @api_version("2.5.0", "2.5.0", _DICT_VERSION_RELATIONSHIP) | ||
471 | def account_unpin(self, id): | ||
472 | """ | ||
473 | Unpin / un-endorse a user. | ||
474 | |||
475 | Returns a :ref:`relationship dict <relationship dict>` containing the updated relationship to the user. | ||
476 | """ | ||
477 | id = self.__unpack_id(id) | ||
478 | url = '/api/v1/accounts/{0}/unpin'.format(str(id)) | ||
479 | return self.__api_request('POST', url) | ||
480 | |||
481 | @api_version("3.2.0", "3.2.0", _DICT_VERSION_RELATIONSHIP) | ||
482 | def account_note_set(self, id, comment): | ||
483 | """ | ||
484 | Set a note (visible to the logged in user only) for the given account. | ||
485 | |||
486 | Returns a :ref:`status dict <status dict>` with the `note` updated. | ||
487 | """ | ||
488 | id = self.__unpack_id(id) | ||
489 | params = self.__generate_params(locals(), ["id"]) | ||
490 | return self.__api_request('POST', '/api/v1/accounts/{0}/note'.format(str(id)), params) | ||
491 | |||
492 | @api_version("3.3.0", "3.3.0", _DICT_VERSION_HASHTAG) | ||
493 | def account_featured_tags(self, id): | ||
494 | """ | ||
495 | Get an account's featured hashtags. | ||
496 | |||
497 | Returns a list of :ref:`hashtag dicts <hashtag dicts>` (NOT `featured tag dicts`_). | ||
498 | """ | ||
499 | id = self.__unpack_id(id) | ||
500 | return self.__api_request('GET', '/api/v1/accounts/{0}/featured_tags'.format(str(id))) | ||