diff options
author | Lorenz Diener <[email protected]> | 2019-06-22 20:59:53 +0200 |
---|---|---|
committer | Lorenz Diener <[email protected]> | 2019-06-22 20:59:53 +0200 |
commit | de9155b9f55103f38b9ab8230fff38f81ecbd3bd (patch) | |
tree | 40d3745a0d3feb10d580de32a4d9fb389eae3a78 | |
parent | a88492bdcf0884b922c50d04c44d909f271ff2ca (diff) | |
download | mastodon.py-de9155b9f55103f38b9ab8230fff38f81ecbd3bd.tar.gz |
Implement and document first half of admin API
-rw-r--r-- | docs/index.rst | 53 | ||||
-rw-r--r-- | mastodon/Mastodon.py | 178 |
2 files changed, 226 insertions, 5 deletions
diff --git a/docs/index.rst b/docs/index.rst index b09b050..75773ce 100644 --- a/docs/index.rst +++ b/docs/index.rst | |||
@@ -263,6 +263,8 @@ User dicts | |||
263 | # set up as their moved-to address. | 263 | # set up as their moved-to address. |
264 | 'bot': # Boolean indicating whether this account is automated. | 264 | 'bot': # Boolean indicating whether this account is automated. |
265 | 'fields': # List of up to four dicts with free-form 'name' and 'value' profile info. | 265 | 'fields': # List of up to four dicts with free-form 'name' and 'value' profile info. |
266 | # For fields with "this is me" type verification, verified_at is set to the | ||
267 | # last verification date (It is None otherwise) | ||
266 | } | 268 | } |
267 | 269 | ||
268 | mastodon.account_verify_credentials()["source"] | 270 | mastodon.account_verify_credentials()["source"] |
@@ -739,6 +741,30 @@ Preference dicts | |||
739 | # content warnings by default | 741 | # content warnings by default |
740 | } | 742 | } |
741 | 743 | ||
744 | |||
745 | Admin account dicts | ||
746 | ~~~~~~~~~~~~~~~~~~~ | ||
747 | .. _admin account dicts: | ||
748 | .. code-block:: python | ||
749 | { | ||
750 | 'id': # The users id, | ||
751 | 'username': # The users username, no leading @ | ||
752 | 'domain': # The users domain | ||
753 | 'created_at': # The time of account creation | ||
754 | 'email': # For local users, the users e-mail | ||
755 | 'ip': # For local users, the users last known IP address | ||
756 | 'role': # 'admin', 'moderator' or None | ||
757 | 'confirmed': # For local users, False if the user has not confirmed their e-mail, True otherwise | ||
758 | 'suspended': # Boolean indicating whether the user has been suspended | ||
759 | 'silenced': # Boolean indicating whether the user has been suspended | ||
760 | 'disabled': # For local users, boolean indicating whether the user has had their login disabled | ||
761 | 'approved': # For local users, False if the user is pending, True otherwise | ||
762 | 'locale': # For local users, the locale the user has set, | ||
763 | 'invite_request': # If the user requested an invite, the invite request comment of that user. (TODO permanent?) | ||
764 | 'invited_by_account_id': # Present if the user was invited by another user and set to the inviting users id. | ||
765 | 'account': # The users account, as a standard account dict | ||
766 | } | ||
767 | |||
742 | App registration and user authentication | 768 | App registration and user authentication |
743 | ---------------------------------------- | 769 | ---------------------------------------- |
744 | Before you can use the mastodon API, you have to register your | 770 | Before you can use the mastodon API, you have to register your |
@@ -1149,6 +1175,33 @@ All crypto utilities require Mastodon.pys optional "webpush" feature dependencie | |||
1149 | .. automethod:: Mastodon.push_subscription_generate_keys | 1175 | .. automethod:: Mastodon.push_subscription_generate_keys |
1150 | .. automethod:: Mastodon.push_subscription_decrypt_push | 1176 | .. automethod:: Mastodon.push_subscription_decrypt_push |
1151 | 1177 | ||
1178 | |||
1179 | Moderation API | ||
1180 | -------------- | ||
1181 | These functions allow you to perform moderation actions on users and generally | ||
1182 | process reports using the API. To do this, you need access to the "admin:read" and/or | ||
1183 | "admin:write" scopes or their more granular variants (both for the application and the | ||
1184 | access token), as well as at least moderator access. Mastodon.py will not request these | ||
1185 | by default, as that would be very dangerous. | ||
1186 | |||
1187 | BIG WARNING: TREAT ANY ACCESS TOKENS THAT HAVE ADMIN CREDENTIALS AS EXTREMELY, MASSIVELY | ||
1188 | SENSITIVE DATA AND MAKE EXTRA SURE TO REVOKE THEM AFTER TESTING, NOT LET THEM SIT IN FILES | ||
1189 | SOMEWHERE, TRACK WHICH ARE ACTIVE, ET CETERA. ANY EXPOSURE OF SUCH ACCESS TOKENS MEANS YOU | ||
1190 | EXPOSE THE PERSONAL DATA OF ALL YOUR USERS TO WHOEVER HAS THESE TOKENS. TREAT THEM WITH | ||
1191 | EXTREME CARE. | ||
1192 | |||
1193 | This is not to say that you should not treat access tokens from admin accounts that do not | ||
1194 | have admin: scopes attached with a lot of care, but be extra careful with those that do. | ||
1195 | |||
1196 | .. automethod:: Mastodon.admin_accounts | ||
1197 | .. automethod:: Mastodon.admin_account | ||
1198 | .. automethod:: Mastodon.admin_account_enable | ||
1199 | .. automethod:: Mastodon.admin_account_approve | ||
1200 | .. automethod:: Mastodon.admin_account_reject | ||
1201 | .. automethod:: Mastodon.admin_account_unsilence | ||
1202 | .. automethod:: Mastodon.admin_account_unsuspend | ||
1203 | .. automethod:: Mastodon.admin_account_moderate | ||
1204 | |||
1152 | Acknowledgements | 1205 | Acknowledgements |
1153 | ---------------- | 1206 | ---------------- |
1154 | Mastodon.py contains work by a large amount of contributors, many of which have | 1207 | Mastodon.py contains work by a large amount of contributors, many of which have |
diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py index 6f84b27..78f8b85 100644 --- a/mastodon/Mastodon.py +++ b/mastodon/Mastodon.py | |||
@@ -167,11 +167,20 @@ class Mastodon: | |||
167 | 'write:blocks', | 167 | 'write:blocks', |
168 | 'write:follows', | 168 | 'write:follows', |
169 | 'write:mutes', | 169 | 'write:mutes', |
170 | ] | 170 | ], |
171 | 'admin:read': [ | ||
172 | 'admin:read:accounts', | ||
173 | 'admin:read:reports', | ||
174 | ], | ||
175 | 'admin:write': [ | ||
176 | 'admin:write:accounts', | ||
177 | 'admin:write:reports', | ||
178 | ], | ||
171 | } | 179 | } |
172 | __VALID_SCOPES = ['read', 'write', 'follow', 'push'] + __SCOPE_SETS['read'] + __SCOPE_SETS['write'] | 180 | __VALID_SCOPES = ['read', 'write', 'follow', 'push', 'admin:read', 'admin:write'] + \ |
181 | __SCOPE_SETS['read'] + __SCOPE_SETS['write'] + __SCOPE_SETS['admin:read'] + __SCOPE_SETS['admin:write'] | ||
173 | 182 | ||
174 | __SUPPORTED_MASTODON_VERSION = "2.8.4" | 183 | __SUPPORTED_MASTODON_VERSION = "2.9.2" |
175 | 184 | ||
176 | # Dict versions | 185 | # Dict versions |
177 | __DICT_VERSION_APPLICATION = "2.7.2" | 186 | __DICT_VERSION_APPLICATION = "2.7.2" |
@@ -593,7 +602,7 @@ class Mastodon: | |||
593 | 602 | ||
594 | Activity is returned for 12 weeks going back from the current week. | 603 | Activity is returned for 12 weeks going back from the current week. |
595 | 604 | ||
596 | Returns a list `activity dicts`_. | 605 | Returns a list of `activity dicts`_. |
597 | """ | 606 | """ |
598 | return self.__api_request('GET', '/api/v1/instance/activity') | 607 | return self.__api_request('GET', '/api/v1/instance/activity') |
599 | 608 | ||
@@ -2318,7 +2327,166 @@ class Mastodon: | |||
2318 | """ | 2327 | """ |
2319 | self.__api_request('DELETE', '/api/v1/push/subscription') | 2328 | self.__api_request('DELETE', '/api/v1/push/subscription') |
2320 | 2329 | ||
2321 | 2330 | ### | |
2331 | # Moderation API | ||
2332 | ### | ||
2333 | @api_version("2.9.1", "2.9.1", "2.9.1") | ||
2334 | def admin_accounts(self, remote=False, by_domain=None, status='active', username=None, display_name=None, email=None, ip=None, staff_only=False, max_id=None, min_id=None, since_id=None, limit=None): | ||
2335 | """ | ||
2336 | Fetches a list of accounts that match given criteria. By default, local accounts are returned. | ||
2337 | |||
2338 | Set `remote` to True to get remote accounts, otherwise local accounts are returned (default: local accounts) | ||
2339 | Set `by_domain` to a domain to get only accounts from that domain. | ||
2340 | Set `status` to one of "active", "pending", "disabled", "silenced" or "suspended" to get only accounts with that moderation status (default: active) | ||
2341 | Set `username` to a string to get only accounts whose username contains this string. | ||
2342 | Set `display_name` to a string to get only accounts whose display name contains this string. | ||
2343 | Set `email` to an email to get only accounts with that email (this only works on local accounts). | ||
2344 | Set `ip` to an ip (as a string, standard v4/v6 notation) to get only accounts whose last active ip is that ip (this only works on local accounts). | ||
2345 | Set `staff_only` to True to only get staff accounts (this only works on local accounts). | ||
2346 | |||
2347 | Note that setting the boolean parameters to False does not mean "give me users to which this does not apply" but | ||
2348 | instead means "I do not care if users have this attribute". | ||
2349 | |||
2350 | Returns a list of `admin account dicts`_. | ||
2351 | """ | ||
2352 | if max_id != None: | ||
2353 | max_id = self.__unpack_id(max_id) | ||
2354 | |||
2355 | if min_id != None: | ||
2356 | min_id = self.__unpack_id(min_id) | ||
2357 | |||
2358 | if since_id != None: | ||
2359 | since_id = self.__unpack_id(since_id) | ||
2360 | |||
2361 | params = self.__generate_params(locals(), ['remote', 'status', 'staff_only']) | ||
2362 | |||
2363 | if remote == True: | ||
2364 | params["remote"] = True | ||
2365 | |||
2366 | mod_statuses = ["active", "pending", "disabled", "silenced", "suspended"] | ||
2367 | if not status in mod_statuses: | ||
2368 | raise ValueError("Invalid moderation status requested.") | ||
2369 | |||
2370 | if staff_only == True: | ||
2371 | params["staff"] = True | ||
2372 | |||
2373 | for mod_status in mod_statuses: | ||
2374 | if status == mod_status: | ||
2375 | params[status] = True | ||
2376 | |||
2377 | return self.__api_request('GET', '/api/v1/admin/accounts', params) | ||
2378 | |||
2379 | def admin_account(self, id): | ||
2380 | """ | ||
2381 | Fetches a single `admin account dict`_ for the user with the given id. | ||
2382 | |||
2383 | Returns that dict. | ||
2384 | """ | ||
2385 | id = self.__unpack_id(id) | ||
2386 | return self.__api_request('GET', '/api/v1/admin/accounts/{0}'.format(id)) | ||
2387 | |||
2388 | def admin_account_enable(self, id): | ||
2389 | """ | ||
2390 | Reenables login for a local account for which login has been disabled. | ||
2391 | |||
2392 | Returns the updated `admin account dict`_. | ||
2393 | """ | ||
2394 | id = self.__unpack_id(id) | ||
2395 | return self.__api_request('POST', '/api/v1/admin/accounts/{0}/enable'.format(id)) | ||
2396 | |||
2397 | def admin_account_approve(self, id): | ||
2398 | """ | ||
2399 | Approves a pending account. | ||
2400 | |||
2401 | Returns the updated `admin account dict`_. | ||
2402 | """ | ||
2403 | id = self.__unpack_id(id) | ||
2404 | return self.__api_request('POST', '/api/v1/admin/accounts/{0}/approve'.format(id)) | ||
2405 | |||
2406 | def admin_account_reject(self, id): | ||
2407 | """ | ||
2408 | Rejects and deletes a pending account. | ||
2409 | |||
2410 | Returns the updated `admin account dict`_ for the account that is now gone. | ||
2411 | """ | ||
2412 | id = self.__unpack_id(id) | ||
2413 | return self.__api_request('POST', '/api/v1/admin/accounts/{0}/reject'.format(id)) | ||
2414 | |||
2415 | def admin_account_unsilence(self, id): | ||
2416 | """ | ||
2417 | Unsilences an account. | ||
2418 | |||
2419 | Returns the updated `admin account dict`_. | ||
2420 | """ | ||
2421 | id = self.__unpack_id(id) | ||
2422 | return self.__api_request('POST', '/api/v1/admin/accounts/{0}/unsilence'.format(id)) | ||
2423 | |||
2424 | def admin_account_unsuspend(self, id): | ||
2425 | """ | ||
2426 | Unsuspends an account. | ||
2427 | |||
2428 | Returns the updated `admin account dict`_. | ||
2429 | """ | ||
2430 | id = self.__unpack_id(id) | ||
2431 | return self.__api_request('POST', '/api/v1/admin/accounts/{0}/unsuspend'.format(id)) | ||
2432 | |||
2433 | def admin_account_moderate(self, id, action=None, report_id=None, warning_preset_id=None, text=None, send_email_notification=True): | ||
2434 | """ | ||
2435 | Perform a moderation action on an account. | ||
2436 | |||
2437 | Valid actions are: | ||
2438 | * "disable" - for a local user, disable login. | ||
2439 | * "silence" - hide the users posts from all public timelines. | ||
2440 | * "suspend" - irreversibly delete all the users posts, past and future. | ||
2441 | If no action is specified, the user is only issued a warning. | ||
2442 | |||
2443 | Specify the id of a report as `report_id` to close the report with this moderation action as the resolution. | ||
2444 | Specify `warning_preset_id` to use a warning preset as the notification text to the user, or `text` to specify text directly. | ||
2445 | If both are specified, they are concatenated (preset first). Note that there is currently no API to retrieve or create | ||
2446 | warning presets. | ||
2447 | |||
2448 | Set `send_email_notification` to False to not send the user an e-mail notification informing them of the moderation action. | ||
2449 | """ | ||
2450 | if action is None: | ||
2451 | action = "none" | ||
2452 | |||
2453 | if send_email_notification == False: | ||
2454 | send_email_notification = None | ||
2455 | |||
2456 | id = self.__unpack_id(id) | ||
2457 | if not report_id is None: | ||
2458 | report_id = self.__unpack_id(report_id) | ||
2459 | |||
2460 | params = self.__generate_params(locals(), ['id', 'action']) | ||
2461 | |||
2462 | params["type"] = action | ||
2463 | |||
2464 | self.__api_request('POST', '/api/v1/admin/accounts/{0}/action'.format(id), params) | ||
2465 | |||
2466 | def admin_reports(self, resolved, account_id, target_account_id): | ||
2467 | pass | ||
2468 | #GET /api/v1/admin/reports Get reports, with params resolved, account_id, target_account_id | ||
2469 | |||
2470 | def admin_report(self, id): | ||
2471 | pass | ||
2472 | #GET /api/v1/admin/reports/:id Get a specific report | ||
2473 | |||
2474 | def admin_report_assign(self, id): | ||
2475 | pass | ||
2476 | #POST /api/v1/admin/reports/:id/assign_to_self Assign report to self | ||
2477 | |||
2478 | def admin_report_unassign(self, id): | ||
2479 | pass | ||
2480 | #POST /api/v1/admin/reports/:id/unassign Unassign report from self | ||
2481 | |||
2482 | def admin_report_reopen(self, id): | ||
2483 | pass | ||
2484 | #POST /api/v1/admin/reports/:id/reopen Re-open report | ||
2485 | |||
2486 | def admin_report_resolve(self, id): | ||
2487 | pass | ||
2488 | #POST /api/v1/admin/reports/:id/resolve Close report | ||
2489 | |||
2322 | ### | 2490 | ### |
2323 | # Push subscription crypto utilities | 2491 | # Push subscription crypto utilities |
2324 | ### | 2492 | ### |