add admin stats APIs

pull/285/head
halcy 2022-11-27 02:43:22 +02:00
rodzic 7331f7774a
commit 5cf0fa27a9
6 zmienionych plików z 436 dodań i 10 usunięć

Wyświetl plik

@ -44,7 +44,7 @@ Refer to mastodon changelog and API docs for details when implementing, add or m
* [x] Add support for incoming edited posts
* [x] Add notifications for posts deleted by moderators <- by email. not actually API relevant.
* [x] Add explore page with trending posts and links
* [ ] Add graphs and retention metrics to admin dashboard
* [x] Add graphs and retention metrics to admin dashboard
* [ ] Add GET /api/v1/accounts/familiar_followers to REST API
* [ ] Add POST /api/v1/accounts/:id/remove_from_followers to REST API
* [x] Add category and rule_ids params to POST /api/v1/reports IN REST API
@ -55,7 +55,7 @@ Refer to mastodon changelog and API docs for details when implementing, add or m
3.5.3
-----
* [ ] Add limited attribute to accounts in REST API
* [later with tool to update dicts] Add limited attribute to accounts in REST API
4.0.0 and beyond
----------------

Wyświetl plik

@ -345,6 +345,18 @@ Toot dicts
'poll': # A poll dict if a poll is attached to this status.
}
Status edit dicts
~~~~~~~~~~~~~~~~~
.. _status edit dict:
.. code-block:: python
mastodonstatus_history(id)[0]
# Returns the following dictionary
{
TODO
}
Mention dicts
~~~~~~~~~~~~~
.. _mention dict:
@ -902,13 +914,37 @@ Admin domain block dicts
'obfuscate': #Boolean. True if domain name is obfuscated when listing.
}
Status edit dicts
~~~~~~~~~~~~~~~~~
.. _status edit dict:
Admin measure dicts
~~~~~~~~~~~~~~~~~~~
.. _admin measure dict:
.. code-block:: python
mastodonstatus_history(id)[0]
api.admin_measures(datetime.now() - timedelta(hours=24*5), datetime.now(), active_users=True)
# Returns the following dictionary
{
TODO
}
Admin dimension dicts
~~~~~~~~~~~~~~~~~~~~~
.. _admin dimension dict:
.. code-block:: python
api.admin_dimensions(datetime.now() - timedelta(hours=24*5), datetime.now(), languages=True)
# Returns the following dictionary
{
TODO
}
Admin retention dicts
~~~~~~~~~~~~~~~~~~~~~
.. _admin retention dict:
.. code-block:: python
api.admin_retention(datetime.now() - timedelta(hours=24*5), datetime.now())
# Returns the following dictionary
{
TODO
@ -1471,6 +1507,11 @@ have admin: scopes attached with a lot of care, but be extra careful with those
.. automethod:: Mastodon.admin_update_domain_block
.. automethod:: Mastodon.admin_delete_domain_block
.. automethod:: Mastodon.admin_measures
.. automethod:: Mastodon.admin_dimensions
.. automethod:: Mastodon.admin_retention
Acknowledgements
----------------
Mastodon.py contains work by a large number of contributors, many of which have

Wyświetl plik

@ -108,7 +108,6 @@ def api_version(created_ver, last_changed_ver, return_value_ver):
raise MastodonVersionError(
"Version check failed (Need version " + version + ")")
elif major == self.mastodon_major and minor > self.mastodon_minor:
print(self.mastodon_minor)
raise MastodonVersionError(
"Version check failed (Need version " + version + ")")
elif major == self.mastodon_major and minor == self.mastodon_minor and patch > self.mastodon_patch:
@ -264,6 +263,9 @@ class Mastodon:
__DICT_VERSION_ANNOUNCEMENT = bigger_version("3.1.0", __DICT_VERSION_REACTION)
__DICT_VERSION_STATUS_EDIT = "3.5.0"
__DICT_VERSION_ADMIN_DOMAIN_BLOCK = "4.0.0"
__DICT_VERSION_ADMIN_MEASURE = "3.5.0"
__DICT_VERSION_ADMIN_DIMENSION = "3.5.0"
__DICT_VERSION_ADMIN_RETENTION = "3.5.0"
###
# Registering apps
@ -432,7 +434,6 @@ class Mastodon:
try_base_url = secret_file.readline().rstrip()
if try_base_url is not None and len(try_base_url) != 0:
try_base_url = Mastodon.__protocolize(try_base_url)
print(self.api_base_url, try_base_url)
if not (self.api_base_url is None or try_base_url == self.api_base_url):
raise MastodonIllegalArgumentError('Mismatch in base URLs between files and/or specified')
self.api_base_url = try_base_url
@ -544,7 +545,6 @@ class Mastodon:
We parse this from the hopefully present "Date" header, but make no effort to compensate for latency.
"""
response = self.__api_request("HEAD", "/", return_response_object=True)
print(response.headers)
if 'Date' in response.headers:
server_time_datetime = dateutil.parser.parse(response.headers['Date'])
@ -3456,6 +3456,130 @@ class Mastodon:
else:
raise AttributeError("You must provide an id of an existing domain block to remove it.")
@api_version("3.5.0", "3.5.0", __DICT_VERSION_ADMIN_MEASURE)
def admin_measures(self, start_at, end_at, active_users=False, new_users=False, interactions=False, opened_reports = False, resolved_reports=False,
tag_accounts=None, tag_uses=None, tag_servers=None, instance_accounts=None, instance_media_attachments=None, instance_reports=None,
instance_statuses=None, instance_follows=None, instance_followers=None):
"""
Retrieves numerical instance information for the time period (at day granularity) between `start_at` and `end_at`.
* `active_users`: Pass true to retrieve the number of active users on your instance within the time period
* `new_users`: Pass true to retrieve the number of users who joined your instance within the time period
* `interactions`: Pass true to retrieve the number of interactions (favourites, boosts, replies) on local statuses within the time period
* `opened_reports`: Pass true to retrieve the number of reports filed within the time period
* `resolved_reports` = Pass true to retrieve the number of reports resolved within the time period
* `tag_accounts`: Pass a tag ID to get the number of accounts which used that tag in at least one status within the time period
* `tag_uses`: Pass a tag ID to get the number of statuses which used that tag within the time period
* `tag_servers`: Pass a tag ID to to get the number of remote origin servers for statuses which used that tag within the time period
* `instance_accounts`: Pass a domain to get the number of accounts originating from that remote domain within the time period
* `instance_media_attachments`: Pass a domain to get the amount of space used by media attachments from that remote domain within the time period
* `instance_reports`: Pass a domain to get the number of reports filed against accounts from that remote domain within the time period
* `instance_statuses`: Pass a domain to get the number of statuses originating from that remote domain within the time period
* `instance_follows`: Pass a domain to get the number of accounts from a remote domain followed by that local user within the time period
* `instance_followers`: Pass a domain to get the number of local accounts followed by accounts from that remote domain within the time period
This API call is relatively expensive - watch your servers load if you want to get a lot of statistical data. Especially the instance_statuses stats
might take a long time to compute and, in fact, time out.
There is currently no way to get tag IDs implemented in Mastodon.py, because the Mastodon public API does not implement one. This will be fixed in a future
release.
Returns a list of `admin measure dicts`_.
"""
params_init = locals()
keys = []
for key in ["active_users", "new_users", "interactions", "opened_reports", "resolved_reports"]:
if params_init[key] == True:
keys.append(key)
params = {}
for key in ["tag_accounts", "tag_uses", "tag_servers"]:
if params_init[key] is not None:
keys.append(key)
params[key] = {"id": self.__unpack_id(params_init[key])}
for key in ["instance_accounts", "instance_media_attachments", "instance_reports", "instance_statuses", "instance_follows", "instance_followers"]:
if params_init[key] is not None:
keys.append(key)
params[key] = {"domain": Mastodon.__deprotocolize(params_init[key]).split("/")[0]}
if len(keys) == 0:
raise MastodonIllegalArgumentError("Must request at least one metric.")
params["keys"] = keys
params["start_at"] = self.__consistent_isoformat_utc(start_at)
params["end_at"] = self.__consistent_isoformat_utc(end_at)
return self.__api_request('POST', '/api/v1/admin/measures', params, use_json=True)
@api_version("3.5.0", "3.5.0", __DICT_VERSION_ADMIN_DIMENSION)
def admin_dimensions(self, start_at, end_at, limit=None, languages=False, sources=False, servers=False, space_usage=False, software_versions=False,
tag_servers=None, tag_languages=None, instance_accounts=None, instance_languages=None):
"""
Retrieves primarily categorical instance information for the time period (at day granularity) between `start_at` and `end_at`.
* `languages`: Pass true to get the most-used languages on this server
* `sources`: Pass true to get the most-used client apps on this server
* `servers`: Pass true to get the remote servers with the most statuses
* `space_usage`: Pass true to get the how much space is used by different components your software stack
* `software_versions`: Pass true to get the version numbers for your software stack
* `tag_servers`: Pass a tag ID to get the most-common servers for statuses including a trending tag
* `tag_languages`: Pass a tag ID to get the most-used languages for statuses including a trending tag
* `instance_accounts`: Pass a domain to get the most-followed accounts from a remote server
* `instance_languages`: Pass a domain to get the most-used languages from a remote server
Pass `limit` to set how many results you want on queries where that makes sense.
This API call is relatively expensive - watch your servers load if you want to get a lot of statistical data.
There is currently no way to get tag IDs implemented in Mastodon.py, because the Mastodon public API does not implement one. This will be fixed in a future
release.
Returns a list of `admin dimensions dicts`_.
"""
params_init = locals()
keys = []
for key in ["languages", "sources", "servers", "space_usage", "software_versions"]:
if params_init[key] == True:
keys.append(key)
params = {}
for key in ["tag_servers", "tag_languages"]:
if params_init[key] is not None:
keys.append(key)
params[key] = {"id": self.__unpack_id(params_init[key])}
for key in ["instance_accounts", "instance_languages"]:
if params_init[key] is not None:
keys.append(key)
params[key] = {"domain": Mastodon.__deprotocolize(params_init[key]).split("/")[0]}
if len(keys) == 0:
raise MastodonIllegalArgumentError("Must request at least one dimension.")
params["keys"] = keys
if limit is not None:
params["limit"] = limit
params["start_at"] = self.__consistent_isoformat_utc(start_at)
params["end_at"] = self.__consistent_isoformat_utc(end_at)
return self.__api_request('POST', '/api/v1/admin/dimensions', params, use_json=True)
@api_version("3.5.0", "3.5.0", __DICT_VERSION_ADMIN_RETENTION)
def admin_retention(self, start_at, end_at, frequency="day"):
"""
Gets user retention statistics (at `frequency` - "day" or "month" - granularity) between `start_at` and `end_at`.
Returns a list of `admin retention dicts`_
"""
if not frequency in ["day", "month"]:
raise MastodonIllegalArgumentError("Frequency must be day or month")
params = {
"start_at": self.__consistent_isoformat_utc(start_at),
"end_at": self.__consistent_isoformat_utc(end_at),
"frequency": frequency
}
return self.__api_request('POST', '/api/v1/admin/retention', params)
###
# Push subscription crypto utilities
###
@ -3942,7 +4066,6 @@ class Mastodon:
if not response_object.ok:
try:
response = response_object.json(object_hook=self.__json_hooks)
print(response)
if isinstance(response, dict) and 'error' in response:
error_msg = response['error']
elif isinstance(response, str):
@ -4348,6 +4471,14 @@ class Mastodon:
base_url = base_url.rstrip("/")
return base_url
@staticmethod
def __deprotocolize(base_url):
"""Internal helper to strip http and https from a URL"""
if base_url.startswith("http://"):
base_url = base_url[7:]
elif base_url.startswith("https://") or base_url.startswith("onion://"):
base_url = base_url[8:]
return base_url
##
# Exceptions

Wyświetl plik

@ -0,0 +1,201 @@
interactions:
- request:
body: '{"instance_accounts": {"domain": "chitter.xyz"}, "instance_media_attachments":
{"domain": "chitter.xyz"}, "instance_reports": {"domain": "chitter.xyz"}, "instance_statuses":
{"domain": "chitter.xyz"}, "instance_follows": {"domain": "chitter.xyz"}, "instance_followers":
{"domain": "chitter.xyz"}, "keys": ["active_users", "new_users", "opened_reports",
"resolved_reports", "instance_accounts", "instance_media_attachments", "instance_reports",
"instance_statuses", "instance_follows", "instance_followers"], "start_at":
"2022-11-22T00:42:51+00:00", "end_at": "2022-11-27T00:42:51+00:00"}'
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Authorization:
- Bearer __MASTODON_PY_TEST_ACCESS_TOKEN_2
Connection:
- keep-alive
Content-Length:
- '587'
Content-Type:
- application/json
User-Agent:
- tests/v311
method: POST
uri: http://localhost:3000/api/v1/admin/measures
response:
body:
string: '[{"key":"active_users","unit":null,"total":"2","previous_total":"0","data":[{"date":"2022-11-22T00:00:00Z","value":"0"},{"date":"2022-11-23T00:00:00Z","value":"0"},{"date":"2022-11-24T00:00:00Z","value":"0"},{"date":"2022-11-25T00:00:00Z","value":"0"},{"date":"2022-11-26T00:00:00Z","value":"2"}]},{"key":"new_users","unit":null,"total":"4","previous_total":"0","data":[{"date":"2022-11-22T00:00:00.000+00:00","value":"0"},{"date":"2022-11-23T00:00:00.000+00:00","value":"0"},{"date":"2022-11-24T00:00:00.000+00:00","value":"0"},{"date":"2022-11-25T00:00:00.000+00:00","value":"0"},{"date":"2022-11-26T00:00:00.000+00:00","value":"4"},{"date":"2022-11-27T00:00:00.000+00:00","value":"0"}]},{"key":"opened_reports","unit":null,"total":"0","previous_total":"0","data":[{"date":"2022-11-22T00:00:00.000+00:00","value":"0"},{"date":"2022-11-23T00:00:00.000+00:00","value":"0"},{"date":"2022-11-24T00:00:00.000+00:00","value":"0"},{"date":"2022-11-25T00:00:00.000+00:00","value":"0"},{"date":"2022-11-26T00:00:00.000+00:00","value":"0"},{"date":"2022-11-27T00:00:00.000+00:00","value":"0"}]},{"key":"resolved_reports","unit":null,"total":"0","previous_total":"0","data":[{"date":"2022-11-22T00:00:00.000+00:00","value":"0"},{"date":"2022-11-23T00:00:00.000+00:00","value":"0"},{"date":"2022-11-24T00:00:00.000+00:00","value":"0"},{"date":"2022-11-25T00:00:00.000+00:00","value":"0"},{"date":"2022-11-26T00:00:00.000+00:00","value":"0"},{"date":"2022-11-27T00:00:00.000+00:00","value":"0"}]},{"key":"instance_accounts","unit":null,"total":"0","data":[{"date":"2022-11-22T00:00:00.000+00:00","value":"0"},{"date":"2022-11-23T00:00:00.000+00:00","value":"0"},{"date":"2022-11-24T00:00:00.000+00:00","value":"0"},{"date":"2022-11-25T00:00:00.000+00:00","value":"0"},{"date":"2022-11-26T00:00:00.000+00:00","value":"0"},{"date":"2022-11-27T00:00:00.000+00:00","value":"0"}]},{"key":"instance_media_attachments","unit":"bytes","total":"0","human_value":"0
Bytes","data":[{"date":"2022-11-22T00:00:00.000+00:00","value":""},{"date":"2022-11-23T00:00:00.000+00:00","value":""},{"date":"2022-11-24T00:00:00.000+00:00","value":""},{"date":"2022-11-25T00:00:00.000+00:00","value":""},{"date":"2022-11-26T00:00:00.000+00:00","value":""},{"date":"2022-11-27T00:00:00.000+00:00","value":""}]},{"key":"instance_reports","unit":null,"total":"0","data":[{"date":"2022-11-22T00:00:00.000+00:00","value":"0"},{"date":"2022-11-23T00:00:00.000+00:00","value":"0"},{"date":"2022-11-24T00:00:00.000+00:00","value":"0"},{"date":"2022-11-25T00:00:00.000+00:00","value":"0"},{"date":"2022-11-26T00:00:00.000+00:00","value":"0"},{"date":"2022-11-27T00:00:00.000+00:00","value":"0"}]},{"key":"instance_statuses","unit":null,"total":"0","data":[{"date":"2022-11-22T00:00:00.000+00:00","value":"0"},{"date":"2022-11-23T00:00:00.000+00:00","value":"0"},{"date":"2022-11-24T00:00:00.000+00:00","value":"0"},{"date":"2022-11-25T00:00:00.000+00:00","value":"0"},{"date":"2022-11-26T00:00:00.000+00:00","value":"0"},{"date":"2022-11-27T00:00:00.000+00:00","value":"0"}]},{"key":"instance_follows","unit":null,"total":"0","data":[{"date":"2022-11-22T00:00:00.000+00:00","value":"0"},{"date":"2022-11-23T00:00:00.000+00:00","value":"0"},{"date":"2022-11-24T00:00:00.000+00:00","value":"0"},{"date":"2022-11-25T00:00:00.000+00:00","value":"0"},{"date":"2022-11-26T00:00:00.000+00:00","value":"0"},{"date":"2022-11-27T00:00:00.000+00:00","value":"0"}]},{"key":"instance_followers","unit":null,"total":"0","data":[{"date":"2022-11-22T00:00:00.000+00:00","value":"0"},{"date":"2022-11-23T00:00:00.000+00:00","value":"0"},{"date":"2022-11-24T00:00:00.000+00:00","value":"0"},{"date":"2022-11-25T00:00:00.000+00:00","value":"0"},{"date":"2022-11-26T00:00:00.000+00:00","value":"0"},{"date":"2022-11-27T00:00:00.000+00:00","value":"0"}]}]'
headers:
Cache-Control:
- no-store
Content-Security-Policy:
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
style-src ''self'' http://localhost:3000 ''nonce-drS6KPeE5pwtqRFGPVh3ww=='';
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
worker-src ''self'' blob: http://localhost:3000'
Content-Type:
- application/json; charset=utf-8
ETag:
- W/"bb40e02b66cfdf5be1ff5a980c8242af"
Referrer-Policy:
- strict-origin-when-cross-origin
Transfer-Encoding:
- chunked
Vary:
- Accept, Origin
X-Content-Type-Options:
- nosniff
X-Download-Options:
- noopen
X-Frame-Options:
- SAMEORIGIN
X-Permitted-Cross-Domain-Policies:
- none
X-Request-Id:
- 11b2cb9c-d3c4-41ba-802d-888e1ee62c9e
X-Runtime:
- '0.540102'
X-XSS-Protection:
- 1; mode=block
status:
code: 200
message: OK
- request:
body: '{"instance_accounts": {"domain": "chitter.xyz"}, "instance_languages":
{"domain": "chitter.xyz"}, "keys": ["languages", "sources", "servers", "space_usage",
"instance_accounts", "instance_languages"], "limit": 3, "start_at": "2022-11-22T00:42:52+00:00",
"end_at": "2022-11-27T00:42:52+00:00"}'
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Authorization:
- Bearer __MASTODON_PY_TEST_ACCESS_TOKEN_2
Connection:
- keep-alive
Content-Length:
- '292'
Content-Type:
- application/json
User-Agent:
- tests/v311
method: POST
uri: http://localhost:3000/api/v1/admin/dimensions
response:
body:
string: '[{"key":"languages","data":[{"key":"de","human_key":"German","value":"1"}]},{"key":"sources","data":[{"key":"web","human_key":"Website","value":"4"}]},{"key":"servers","data":[]},{"key":"space_usage","data":[{"key":"postgresql","human_key":"PostgreSQL","value":"16610095","unit":"bytes","human_value":"15.8
MB"},{"key":"redis","human_key":"Redis","value":"1560216","unit":"bytes","human_value":"1.49
MB"},{"key":"media","human_key":"Media storage","value":"0","unit":"bytes","human_value":"0
Bytes"}]},{"key":"instance_accounts","data":[]},{"key":"instance_languages","data":[]}]'
headers:
Cache-Control:
- no-store
Content-Security-Policy:
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
style-src ''self'' http://localhost:3000 ''nonce-tTPpzIcGAZb7y2EXyfEsFg=='';
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
worker-src ''self'' blob: http://localhost:3000'
Content-Type:
- application/json; charset=utf-8
ETag:
- W/"b5c3e0d37fd2fdab9859f566f5b2fa2e"
Referrer-Policy:
- strict-origin-when-cross-origin
Transfer-Encoding:
- chunked
Vary:
- Accept, Origin
X-Content-Type-Options:
- nosniff
X-Download-Options:
- noopen
X-Frame-Options:
- SAMEORIGIN
X-Permitted-Cross-Domain-Policies:
- none
X-Request-Id:
- 7332d9ca-00cb-4eaf-9d95-ee3baf8414f9
X-Runtime:
- '0.066790'
X-XSS-Protection:
- 1; mode=block
status:
code: 200
message: OK
- request:
body: start_at=2022-11-17T00%3A42%3A52%2B00%3A00&end_at=2022-11-27T00%3A42%3A52%2B00%3A00&frequency=day
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Authorization:
- Bearer __MASTODON_PY_TEST_ACCESS_TOKEN_2
Connection:
- keep-alive
Content-Length:
- '97'
Content-Type:
- application/x-www-form-urlencoded
User-Agent:
- tests/v311
method: POST
uri: http://localhost:3000/api/v1/admin/retention
response:
body:
string: '[{"period":"2022-11-17T00:00:00+00:00","frequency":"day","data":[{"date":"2022-11-17T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-18T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-19T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-20T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-21T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-22T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-23T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-24T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-25T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-26T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-27T00:00:00+00:00","rate":0.0,"value":"0"}]},{"period":"2022-11-18T00:00:00+00:00","frequency":"day","data":[{"date":"2022-11-18T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-19T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-20T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-21T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-22T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-23T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-24T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-25T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-26T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-27T00:00:00+00:00","rate":0.0,"value":"0"}]},{"period":"2022-11-19T00:00:00+00:00","frequency":"day","data":[{"date":"2022-11-19T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-20T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-21T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-22T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-23T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-24T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-25T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-26T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-27T00:00:00+00:00","rate":0.0,"value":"0"}]},{"period":"2022-11-20T00:00:00+00:00","frequency":"day","data":[{"date":"2022-11-20T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-21T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-22T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-23T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-24T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-25T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-26T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-27T00:00:00+00:00","rate":0.0,"value":"0"}]},{"period":"2022-11-21T00:00:00+00:00","frequency":"day","data":[{"date":"2022-11-21T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-22T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-23T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-24T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-25T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-26T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-27T00:00:00+00:00","rate":0.0,"value":"0"}]},{"period":"2022-11-22T00:00:00+00:00","frequency":"day","data":[{"date":"2022-11-22T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-23T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-24T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-25T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-26T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-27T00:00:00+00:00","rate":0.0,"value":"0"}]},{"period":"2022-11-23T00:00:00+00:00","frequency":"day","data":[{"date":"2022-11-23T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-24T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-25T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-26T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-27T00:00:00+00:00","rate":0.0,"value":"0"}]},{"period":"2022-11-24T00:00:00+00:00","frequency":"day","data":[{"date":"2022-11-24T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-25T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-26T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-27T00:00:00+00:00","rate":0.0,"value":"0"}]},{"period":"2022-11-25T00:00:00+00:00","frequency":"day","data":[{"date":"2022-11-25T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-26T00:00:00+00:00","rate":0.0,"value":"0"},{"date":"2022-11-27T00:00:00+00:00","rate":0.0,"value":"0"}]},{"period":"2022-11-26T00:00:00+00:00","frequency":"day","data":[{"date":"2022-11-26T00:00:00+00:00","rate":0.5,"value":"2"},{"date":"2022-11-27T00:00:00+00:00","rate":0.0,"value":"0"}]},{"period":"2022-11-27T00:00:00+00:00","frequency":"day","data":[{"date":"2022-11-27T00:00:00+00:00","rate":0.0,"value":"0"}]}]'
headers:
Cache-Control:
- no-store
Content-Security-Policy:
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
style-src ''self'' http://localhost:3000 ''nonce-AkyM5KkEra/OBSMZSu3SqQ=='';
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
worker-src ''self'' blob: http://localhost:3000'
Content-Type:
- application/json; charset=utf-8
ETag:
- W/"c607f49eb27c19d561dab0434594a06e"
Referrer-Policy:
- strict-origin-when-cross-origin
Transfer-Encoding:
- chunked
Vary:
- Accept, Origin
X-Content-Type-Options:
- nosniff
X-Download-Options:
- noopen
X-Frame-Options:
- SAMEORIGIN
X-Permitted-Cross-Domain-Policies:
- none
X-Request-Id:
- 67a94c6b-e1fe-4c60-90c5-478c98e3e0f7
X-Runtime:
- '0.435749'
X-XSS-Protection:
- 1; mode=block
status:
code: 200
message: OK
version: 1

Wyświetl plik

@ -27,6 +27,11 @@ UPDATE users SET
encrypted_password = '$2a$10$8eAdhF69RiZiV0puZ.8iOOgMqBACmwJu8Z9X4CiN91iwRXbeC2jvi'
WHERE email = 'mastodonpy_test_2@localhost:3000';
UPDATE users SET
locale = 'de',
encrypted_password = '$2a$10$8eAdhF69RiZiV0puZ.8iOOgMqBACmwJu8Z9X4CiN91iwRXbeC2jvi'
WHERE email = 'zerocool@example.com';
INSERT INTO oauth_applications (
id,
name,

Wyświetl plik

@ -1,5 +1,7 @@
import pytest
import time
from datetime import datetime, timedelta
from mastodon import MastodonIllegalArgumentError
@pytest.mark.vcr()
def test_admin_accounts(api2):
@ -134,3 +136,49 @@ def test_admin_domain_blocks(api2):
assert block3.private_comment == "jk ilu <3"
api2.admin_delete_domain_block(block2)
assert not block3.id in map(lambda x: x.id, api2.admin_domain_blocks())
@pytest.mark.vcr()
def test_admin_stats(api2):
assert api2.admin_measures(
datetime.now() - timedelta(hours=24*5),
datetime.now(),
active_users=True,
new_users=True,
opened_reports=True,
resolved_reports=True,
instance_accounts="chitter.xyz",
instance_media_attachments="chitter.xyz",
instance_reports="http://chitter.xyz/",
instance_statuses="chitter.xyz",
instance_follows="http://chitter.xyz",
instance_followers="chitter.xyz",
#tag_accounts=0,
#tag_uses=0,
#tag_servers=0,
)
assert api2.admin_dimensions(
datetime.now() - timedelta(hours=24*5),
datetime.now(),
limit=3,
languages=True,
sources=True,
servers=True,
space_usage=True,
#tag_servers=0,
#tag_languages=0,
instance_accounts="chitter.xyz",
instance_languages="https://chitter.xyz"
)
api2.admin_retention(
datetime.now() - timedelta(days=10),
datetime.now()
)
with pytest.raises(MastodonIllegalArgumentError):
api2.admin_retention(
datetime.now() - timedelta(days=10),
datetime.now(),
frequency="dayz"
)