masto-bridges/masto_bridges/post.py

116 lines
3.4 KiB
Python

from typing import Optional, Literal, TYPE_CHECKING
from datetime import datetime, timedelta
from pydantic import BaseModel
import re
from bs4 import BeautifulSoup
if TYPE_CHECKING:
from vobject.icalendar import RecurringComponent
from masto_bridges.repo import Commit
from masto_bridges.models import Account
from masto_bridges.caldav import Event
class Status(BaseModel):
"""
Model of a toot on mastodon
See: https://mastodonpy.readthedocs.io/en/stable/#toot-dicts
"""
id: int
url: str
account: Account
content: str
visibility: Literal['public', 'unlisted', 'private', 'direct']
created_at:datetime
in_reply_to_id: Optional[int] = None
in_reply_to_account_id: Optional[int] = None
spoiler_text: Optional[str] = None
reblog: Optional['Status'] = None
def __init__(self, **kwargs):
if kwargs.get('url', None) is None:
# try using the uri
kwargs['url'] = kwargs['uri']
super(Status, self).__init__(**kwargs)
class Config:
extra='ignore'
class Post(BaseModel):
#timestamp: Optional[datetime] = None
text:str
status:Optional[Status] = None
commit:Optional[Commit] = None
cal_user:Optional[str] = None
cal_url:Optional[str] = None
@classmethod
def from_commit(cls, commit:Commit) -> 'Post':
text = '\n'.join([commit.subject, commit.body])
return Post(text=text, commit=commit)
@classmethod
def from_status(cls, status:Status) -> 'Post':
# if this is a boost, get the original status
if status.reblog:
date = status.created_at
status = status.reblog
status.created_at = date
soup = BeautifulSoup(status.content, 'lxml')
# replace with double line breaks
pars = [p.text for p in soup.find_all('p')]
text = '\n\n'.join(pars)
return Post(text=text, status=status)
@classmethod
def from_vevent(cls, event:'RecurringComponent'):
user=event.summary.value
text = event.description.value
try:
url = event.location.value
except AttributeError:
url = None
return Post(text=text, cal_user=user, cal_url=url)
def format_masto(self) -> str:
"""
Format a post to go from git -> masto.
Needs to have a :attr:`.commit` attribute!
Does not split the body text into multiple toots.
That should be handled in the posting action
Example:
git-social: https://{repo_url}/commits/{hash}
{subject line}
{body}
"""
if self.commit is not None:
return f"xpost from git-social: {self.commit.url}\n---\n{self.text}"""
elif self.cal_user is not None:
return f"xpost from a calendar\n---\n{self.text}"""
else:
return self.text
def format_commit(self) -> str:
"""
Add a link back to original masto post split by double lines
"""
return f"xpost from mastodon: {self.status.url}\n\n{self.text}"
def format_caldav(self) -> Event:
"""
Format a mastodon post for posting to CALDAV
"""
return Event(
dtstart=self.status.created_at,
dtend = self.status.created_at + timedelta(minutes=5),
location = self.status.url,
summary= self.status.account.acct,
description = self.text
)