Resolve "Mastodon integration"

This commit is contained in:
Fabio Manganiello 2021-11-07 01:00:29 +01:00
parent 6db070db1c
commit acdc636b1f
8 changed files with 1764 additions and 2 deletions

View file

@ -5,6 +5,10 @@ Given the high speed of development in the first phase, changes are being report
## [Unreleased] ## [Unreleased]
### Added
- Added Mastodon integration.
### Fixed ### Fixed
- Fixed `switchbot.status` method in case of virtual devices. - Fixed `switchbot.status` method in case of virtual devices.

View file

@ -0,0 +1,5 @@
``mastodon``
============
.. automodule:: platypush.plugins.mastodon
:members:

View file

@ -72,6 +72,7 @@ Plugins
platypush/plugins/luma.oled.rst platypush/plugins/luma.oled.rst
platypush/plugins/mail.imap.rst platypush/plugins/mail.imap.rst
platypush/plugins/mail.smtp.rst platypush/plugins/mail.smtp.rst
platypush/plugins/mastodon.rst
platypush/plugins/media.chromecast.rst platypush/plugins/media.chromecast.rst
platypush/plugins/media.gstreamer.rst platypush/plugins/media.gstreamer.rst
platypush/plugins/media.kodi.rst platypush/plugins/media.kodi.rst

View file

@ -1,7 +1,6 @@
import datetime import datetime
import json import json
import logging import logging
from typing import Dict, Optional
from flask import Blueprint, request, abort, jsonify from flask import Blueprint, request, abort, jsonify
@ -18,7 +17,7 @@ __routes__ = [
@auth.route('/auth', methods=['POST']) @auth.route('/auth', methods=['POST'])
def auth_endpoint() -> Dict[str, Optional[str]]: def auth_endpoint():
""" """
Authentication endpoint. It validates the user credentials provided over a JSON payload with the following Authentication endpoint. It validates the user credentials provided over a JSON payload with the following
structure: structure:

View file

@ -0,0 +1,46 @@
from threading import RLock
from typing import Optional
from platypush.config import Config
from platypush.context import get_backend, get_plugin
_app_tunnel_lock = RLock()
_app_tunnel_url: Optional[str] = None
def _get_http_port() -> int:
http = None
if Config.get('backend.http'):
http = get_backend('http')
assert http, 'The http backend is required in order to subscribe to notifications'
return http.port
def create_ngrok_tunnel() -> str:
"""
This method creates an ngrok tunnel for the local web application,
useful to register public HTTPS callback URLs on the fly from plugins
and backends.
"""
global _app_tunnel_url
with _app_tunnel_lock:
if _app_tunnel_url:
return _app_tunnel_url
local_port = _get_http_port()
ngrok = None
if Config.get('ngrok'):
ngrok = get_plugin('ngrok')
assert ngrok, 'The ngrok plugin is required in order to subscribe to notifications'
tunnel_response = ngrok.create_tunnel(
resource=local_port,
protocol='http',
bind_tls=True,
).output
_app_tunnel_url = tunnel_response.get('url')
assert _app_tunnel_url, 'Unable to create an ngrok tunnel'
return _app_tunnel_url

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,4 @@
manifest:
events: {}
package: platypush.plugins.mastodon
type: plugin

View file

@ -0,0 +1,201 @@
from random import randint
from marshmallow import fields, missing
from marshmallow.schema import Schema
from marshmallow.validate import OneOf
from platypush.schemas import DateTime, Date, StrippedString
notification_types = ['follow', 'favourite', 'reblog', 'mention', 'poll', 'follow_request']
list_reply_policies = ['none', 'followed', 'list']
class MastodonSchema(Schema):
pass
class MastodonAccountSchema(MastodonSchema):
id = fields.String(
dump_only=True,
metadata=dict(
example=''.join([f'{randint(1, 9)}' for _ in range(18)]),
)
)
username = fields.String(
metadata=dict(
example='admin',
)
)
url = fields.URL()
avatar = fields.URL()
header = fields.URL()
followers_count = fields.Int(dump_only=True)
following_count = fields.Int(dump_only=True)
note = fields.String()
display_name = StrippedString(
metadata=dict(
example='Name Surname',
)
)
locked = fields.Boolean()
bot = fields.Boolean()
discoverable = fields.Boolean()
group = fields.Boolean()
created_at = DateTime(dump_only=True)
last_status_at = DateTime(dump_only=True)
class MastodonFeaturedHashtagSchema(MastodonSchema):
id = fields.Int(dump_only=True)
name = fields.String()
statuses_count = fields.Int(dump_only=True)
last_status = DateTime(dump_only=True)
class MastodonHashtagHistorySchema(MastodonSchema):
day = Date()
uses = fields.Int()
accounts = fields.Int()
class MastodonHashtagSchema(MastodonSchema):
name = fields.String(metadata=dict(example='hashtag'))
url = fields.URL()
history = fields.Nested(
MastodonHashtagHistorySchema, many=True, default=missing
)
class MastodonMediaSchema(MastodonSchema):
id = fields.String(dump_only=True)
description = StrippedString()
type = fields.String(dump_only=True, metadata={'example': 'image'})
url = fields.URL(dump_only=True)
preview_url = fields.URL(dump_only=True)
remote_url = fields.URL(dump_only=True)
preview_remote_url = fields.URL(dump_only=True)
meta = fields.Dict()
class MastodonStatusSchema(MastodonSchema):
id = fields.String(
dump_only=True,
metadata=dict(
example=''.join([f'{randint(1, 9)}' for _ in range(18)]),
)
)
in_reply_to_id = fields.String(
dump_only=True,
allow_none=True,
metadata=dict(
example=''.join([f'{randint(1, 9)}' for _ in range(18)]),
)
)
in_reply_to_account_id = fields.String(
dump_only=True,
allow_none=True,
metadata=dict(
example=''.join([f'{randint(1, 9)}' for _ in range(18)]),
)
)
url = fields.URL(dump_only=True)
content = fields.String(allow_none=False)
account = fields.Nested(MastodonAccountSchema, dump_only=True)
attachments = fields.Nested(
MastodonMediaSchema,
many=True,
dump_only=True,
attribute='media_attachments',
)
hashtags = fields.Nested(
MastodonHashtagSchema, many=True,
attribute='tags', dump_only=True
)
replies_count = fields.Int(dump_only=True)
reblogs_count = fields.Int(dump_only=True)
favourites_count = fields.Int(dump_only=True)
sensitive = fields.Boolean()
favourited = fields.Boolean()
reblogged = fields.Boolean()
muted = fields.Boolean()
bookmarked = fields.Boolean()
pinned = fields.Boolean()
created_at = DateTime(dump_only=True)
class MastodonSearchSchema(MastodonSchema):
accounts = fields.Nested(MastodonAccountSchema, many=True)
statuses = fields.Nested(MastodonStatusSchema, many=True)
hashtags = fields.Nested(MastodonHashtagSchema, many=True)
class MastodonAccountCreationSchema(MastodonSchema):
access_token = fields.String(dump_only=True)
token_type = fields.String(dump_only=True, metadata={'example': 'Bearer'})
scope = fields.String(dump_only=True, metadata={'example': 'read write follow push'})
created_at = DateTime(dump_only=True)
class MastodonAccountListSchema(MastodonSchema):
id = fields.Int(dump_only=True)
title = StrippedString()
class MastodonFilterSchema(MastodonSchema):
id = fields.Int(dump_only=True)
phrase = StrippedString()
whole_word = fields.Boolean()
irreversible = fields.Boolean()
expires_at = DateTime(allow_none=True)
context = fields.List(
fields.String(validate=OneOf(['home', 'notifications', 'public', 'thread'])),
metadata={
'example': 'Which context(s) this filter applies to. '
'Possible values: home, notifications, public, thread',
}
)
class MastodonConversationSchema(MastodonSchema):
id = fields.Int(dump_only=True)
unread = fields.Boolean()
accounts = fields.Nested(MastodonAccountSchema, many=True)
last_status = fields.Nested(MastodonStatusSchema)
class MastodonListSchema(MastodonSchema):
id = fields.Int(dump_only=True)
title = StrippedString()
replies_policy = fields.String(validate=OneOf(list_reply_policies))
class MastodonMentionSchema(MastodonSchema):
id = fields.Int(dump_only=True)
username = StrippedString(metadata=dict(example='user'))
url = fields.URL(metadata=dict(example='https://mastodon.social/@user'))
class MastodonNotificationSchema(MastodonSchema):
id = fields.String(dump_only=True)
type = fields.String(validate=OneOf(notification_types))
account = fields.Nested(MastodonAccountSchema)
status = fields.Nested(MastodonStatusSchema)
mention = fields.Nested(MastodonMentionSchema)
created_at = DateTime(dump_only=True)
class MastodonSubscriptionNotificationTypes(MastodonSchema):
follow = fields.Boolean()
reblog = fields.Boolean()
mention = fields.Boolean()
favourite = fields.Boolean()
poll = fields.Boolean()