kopia lustrzana https://github.com/halcy/Mastodon.py
add admin stats APIs
rodzic
7331f7774a
commit
5cf0fa27a9
4
TODO.md
4
TODO.md
|
@ -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 support for incoming edited posts
|
||||||
* [x] Add notifications for posts deleted by moderators <- by email. not actually API relevant.
|
* [x] Add notifications for posts deleted by moderators <- by email. not actually API relevant.
|
||||||
* [x] Add explore page with trending posts and links
|
* [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 GET /api/v1/accounts/familiar_followers to REST API
|
||||||
* [ ] Add POST /api/v1/accounts/:id/remove_from_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
|
* [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
|
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
|
4.0.0 and beyond
|
||||||
----------------
|
----------------
|
||||||
|
|
|
@ -345,6 +345,18 @@ Toot dicts
|
||||||
'poll': # A poll dict if a poll is attached to this status.
|
'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 dicts
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
.. _mention dict:
|
.. _mention dict:
|
||||||
|
@ -902,13 +914,37 @@ Admin domain block dicts
|
||||||
'obfuscate': #Boolean. True if domain name is obfuscated when listing.
|
'obfuscate': #Boolean. True if domain name is obfuscated when listing.
|
||||||
}
|
}
|
||||||
|
|
||||||
Status edit dicts
|
Admin measure dicts
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
.. _status edit dict:
|
.. _admin measure dict:
|
||||||
|
|
||||||
.. code-block:: python
|
.. 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
|
# Returns the following dictionary
|
||||||
{
|
{
|
||||||
TODO
|
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_update_domain_block
|
||||||
.. automethod:: Mastodon.admin_delete_domain_block
|
.. automethod:: Mastodon.admin_delete_domain_block
|
||||||
|
|
||||||
|
.. automethod:: Mastodon.admin_measures
|
||||||
|
.. automethod:: Mastodon.admin_dimensions
|
||||||
|
.. automethod:: Mastodon.admin_retention
|
||||||
|
|
||||||
|
|
||||||
Acknowledgements
|
Acknowledgements
|
||||||
----------------
|
----------------
|
||||||
Mastodon.py contains work by a large number of contributors, many of which have
|
Mastodon.py contains work by a large number of contributors, many of which have
|
||||||
|
|
|
@ -108,7 +108,6 @@ def api_version(created_ver, last_changed_ver, return_value_ver):
|
||||||
raise MastodonVersionError(
|
raise MastodonVersionError(
|
||||||
"Version check failed (Need version " + version + ")")
|
"Version check failed (Need version " + version + ")")
|
||||||
elif major == self.mastodon_major and minor > self.mastodon_minor:
|
elif major == self.mastodon_major and minor > self.mastodon_minor:
|
||||||
print(self.mastodon_minor)
|
|
||||||
raise MastodonVersionError(
|
raise MastodonVersionError(
|
||||||
"Version check failed (Need version " + version + ")")
|
"Version check failed (Need version " + version + ")")
|
||||||
elif major == self.mastodon_major and minor == self.mastodon_minor and patch > self.mastodon_patch:
|
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_ANNOUNCEMENT = bigger_version("3.1.0", __DICT_VERSION_REACTION)
|
||||||
__DICT_VERSION_STATUS_EDIT = "3.5.0"
|
__DICT_VERSION_STATUS_EDIT = "3.5.0"
|
||||||
__DICT_VERSION_ADMIN_DOMAIN_BLOCK = "4.0.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
|
# Registering apps
|
||||||
|
@ -432,7 +434,6 @@ class Mastodon:
|
||||||
try_base_url = secret_file.readline().rstrip()
|
try_base_url = secret_file.readline().rstrip()
|
||||||
if try_base_url is not None and len(try_base_url) != 0:
|
if try_base_url is not None and len(try_base_url) != 0:
|
||||||
try_base_url = Mastodon.__protocolize(try_base_url)
|
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):
|
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')
|
raise MastodonIllegalArgumentError('Mismatch in base URLs between files and/or specified')
|
||||||
self.api_base_url = try_base_url
|
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.
|
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)
|
response = self.__api_request("HEAD", "/", return_response_object=True)
|
||||||
print(response.headers)
|
|
||||||
if 'Date' in response.headers:
|
if 'Date' in response.headers:
|
||||||
server_time_datetime = dateutil.parser.parse(response.headers['Date'])
|
server_time_datetime = dateutil.parser.parse(response.headers['Date'])
|
||||||
|
|
||||||
|
@ -3456,6 +3456,130 @@ class Mastodon:
|
||||||
else:
|
else:
|
||||||
raise AttributeError("You must provide an id of an existing domain block to remove it.")
|
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
|
# Push subscription crypto utilities
|
||||||
###
|
###
|
||||||
|
@ -3942,7 +4066,6 @@ class Mastodon:
|
||||||
if not response_object.ok:
|
if not response_object.ok:
|
||||||
try:
|
try:
|
||||||
response = response_object.json(object_hook=self.__json_hooks)
|
response = response_object.json(object_hook=self.__json_hooks)
|
||||||
print(response)
|
|
||||||
if isinstance(response, dict) and 'error' in response:
|
if isinstance(response, dict) and 'error' in response:
|
||||||
error_msg = response['error']
|
error_msg = response['error']
|
||||||
elif isinstance(response, str):
|
elif isinstance(response, str):
|
||||||
|
@ -4348,6 +4471,14 @@ class Mastodon:
|
||||||
base_url = base_url.rstrip("/")
|
base_url = base_url.rstrip("/")
|
||||||
return base_url
|
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
|
# Exceptions
|
||||||
|
|
|
@ -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
|
|
@ -27,6 +27,11 @@ UPDATE users SET
|
||||||
encrypted_password = '$2a$10$8eAdhF69RiZiV0puZ.8iOOgMqBACmwJu8Z9X4CiN91iwRXbeC2jvi'
|
encrypted_password = '$2a$10$8eAdhF69RiZiV0puZ.8iOOgMqBACmwJu8Z9X4CiN91iwRXbeC2jvi'
|
||||||
WHERE email = 'mastodonpy_test_2@localhost:3000';
|
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 (
|
INSERT INTO oauth_applications (
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import pytest
|
import pytest
|
||||||
import time
|
import time
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from mastodon import MastodonIllegalArgumentError
|
||||||
|
|
||||||
@pytest.mark.vcr()
|
@pytest.mark.vcr()
|
||||||
def test_admin_accounts(api2):
|
def test_admin_accounts(api2):
|
||||||
|
@ -134,3 +136,49 @@ def test_admin_domain_blocks(api2):
|
||||||
assert block3.private_comment == "jk ilu <3"
|
assert block3.private_comment == "jk ilu <3"
|
||||||
api2.admin_delete_domain_block(block2)
|
api2.admin_delete_domain_block(block2)
|
||||||
assert not block3.id in map(lambda x: x.id, api2.admin_domain_blocks())
|
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"
|
||||||
|
)
|
Ładowanie…
Reference in New Issue