mirror of
https://git.sr.ht/~tsileo/microblog.pub
synced 2024-11-15 03:04:28 +00:00
Support actor update
This commit is contained in:
parent
cc89b0b584
commit
7f4be2cbc2
7 changed files with 55 additions and 5 deletions
|
@ -22,10 +22,13 @@
|
||||||
- Compatible with [Mastodon](https://joinmastodon.org/) and others ([Pleroma](https://pleroma.social/), Misskey, Plume, PixelFed, Hubzilla...)
|
- Compatible with [Mastodon](https://joinmastodon.org/) and others ([Pleroma](https://pleroma.social/), Misskey, Plume, PixelFed, Hubzilla...)
|
||||||
- Exposes your outbox as a basic microblog
|
- Exposes your outbox as a basic microblog
|
||||||
- Support all content types from the Fediverse (`Note`, `Article`, `Page`, `Video`, `Image`, `Question`...)
|
- Support all content types from the Fediverse (`Note`, `Article`, `Page`, `Video`, `Image`, `Question`...)
|
||||||
|
- Markdown support
|
||||||
|
- Server-side code syntax highlighting
|
||||||
- Comes with an admin UI with notifications and the stream of people you follow
|
- Comes with an admin UI with notifications and the stream of people you follow
|
||||||
- Private "bookmark" support
|
- Private "bookmark" support
|
||||||
- List support
|
- List support
|
||||||
- Allows you to attach files to your notes
|
- Allows you to attach files to your notes
|
||||||
|
- Custom emojus
|
||||||
- Cares about your privacy
|
- Cares about your privacy
|
||||||
- The image upload endpoint strips EXIF meta data before storing the file
|
- The image upload endpoint strips EXIF meta data before storing the file
|
||||||
- Every attachment/media is cached (or proxied) by the server
|
- Every attachment/media is cached (or proxied) by the server
|
||||||
|
|
|
@ -25,6 +25,7 @@ from core.activitypub import _actor_hash
|
||||||
from core.activitypub import _add_answers_to_question
|
from core.activitypub import _add_answers_to_question
|
||||||
from core.activitypub import _cache_actor_icon
|
from core.activitypub import _cache_actor_icon
|
||||||
from core.activitypub import is_from_outbox
|
from core.activitypub import is_from_outbox
|
||||||
|
from core.activitypub import new_context
|
||||||
from core.activitypub import post_to_outbox
|
from core.activitypub import post_to_outbox
|
||||||
from core.activitypub import save_reply
|
from core.activitypub import save_reply
|
||||||
from core.activitypub import update_cached_actor
|
from core.activitypub import update_cached_actor
|
||||||
|
@ -47,6 +48,7 @@ from core.shared import _Response
|
||||||
from core.shared import back
|
from core.shared import back
|
||||||
from core.shared import p
|
from core.shared import p
|
||||||
from core.tasks import Tasks
|
from core.tasks import Tasks
|
||||||
|
from utils import now
|
||||||
from utils import opengraph
|
from utils import opengraph
|
||||||
from utils.media import is_video
|
from utils.media import is_video
|
||||||
from utils.webmentions import discover_webmention_endpoint
|
from utils.webmentions import discover_webmention_endpoint
|
||||||
|
@ -102,6 +104,28 @@ def task_update_question() -> _Response:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route("/task/send_actor_update", methods=["POST"])
|
||||||
|
def task_send_actor_update() -> _Response:
|
||||||
|
task = p.parse(flask.request)
|
||||||
|
app.logger.info(f"task={task!r}")
|
||||||
|
try:
|
||||||
|
update = ap.Update(
|
||||||
|
actor=MY_PERSON.id,
|
||||||
|
object=MY_PERSON.to_dict(),
|
||||||
|
to=[MY_PERSON.followers],
|
||||||
|
cc=[ap.AS_PUBLIC],
|
||||||
|
published=now(),
|
||||||
|
context=new_context(),
|
||||||
|
)
|
||||||
|
|
||||||
|
post_to_outbox(update)
|
||||||
|
except Exception as err:
|
||||||
|
app.logger.exception(f"failed to send actor update")
|
||||||
|
raise TaskError() from err
|
||||||
|
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route("/task/fetch_og_meta", methods=["POST"])
|
@blueprint.route("/task/fetch_og_meta", methods=["POST"])
|
||||||
def task_fetch_og_meta() -> _Response:
|
def task_fetch_og_meta() -> _Response:
|
||||||
task = p.parse(flask.request)
|
task = p.parse(flask.request)
|
||||||
|
|
|
@ -69,6 +69,7 @@ with open(os.path.join(KEY_DIR, "me.yml")) as f:
|
||||||
ICON_URL = conf["icon_url"]
|
ICON_URL = conf["icon_url"]
|
||||||
PASS = conf["pass"]
|
PASS = conf["pass"]
|
||||||
|
|
||||||
|
PROFILE_METADATA = conf.get("profile_metadata", {})
|
||||||
HIDE_FOLLOWING = conf.get("hide_following", True)
|
HIDE_FOLLOWING = conf.get("hide_following", True)
|
||||||
|
|
||||||
# Theme-related config
|
# Theme-related config
|
||||||
|
@ -130,8 +131,8 @@ def _admin_jwt_token() -> str:
|
||||||
ADMIN_API_KEY = get_secret_key("admin_api_key", _admin_jwt_token)
|
ADMIN_API_KEY = get_secret_key("admin_api_key", _admin_jwt_token)
|
||||||
|
|
||||||
attachments = []
|
attachments = []
|
||||||
if conf.get("profile_metadata"):
|
if PROFILE_METADATA:
|
||||||
for key, value in conf["profile_metadata"].items():
|
for key, value in PROFILE_METADATA.items():
|
||||||
attachments.append(
|
attachments.append(
|
||||||
{"type": "PropertyValue", "name": key, "value": linkify(value)}
|
{"type": "PropertyValue", "name": key, "value": linkify(value)}
|
||||||
)
|
)
|
||||||
|
@ -176,7 +177,7 @@ BLACKLIST = conf.get("blacklist", [])
|
||||||
DISABLE_WEBMENTIONS = conf.get("disable_webmentions", False)
|
DISABLE_WEBMENTIONS = conf.get("disable_webmentions", False)
|
||||||
|
|
||||||
# By default, we keep 14 of inbox data ; outbox is kept forever (along with bookmarked stuff, outbox replies, liked...)
|
# By default, we keep 14 of inbox data ; outbox is kept forever (along with bookmarked stuff, outbox replies, liked...)
|
||||||
DAYS_TO_KEEP = 14
|
DAYS_TO_KEEP = int(conf.get("days_to_keep", 14))
|
||||||
|
|
||||||
# Load custom emojis (stored in static/emojis)
|
# Load custom emojis (stored in static/emojis)
|
||||||
_load_emojis(ROOT_DIR, BASE_URL)
|
_load_emojis(ROOT_DIR, BASE_URL)
|
||||||
|
|
|
@ -78,7 +78,7 @@ def _answer_key(choice: str) -> str:
|
||||||
return h.hexdigest()
|
return h.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def _actor_hash(actor: ap.ActivityType) -> str:
|
def _actor_hash(actor: ap.ActivityType, local: bool = False) -> str:
|
||||||
"""Used to know when to update the meta actor cache, like an "actor version"."""
|
"""Used to know when to update the meta actor cache, like an "actor version"."""
|
||||||
h = hashlib.new("sha1")
|
h = hashlib.new("sha1")
|
||||||
h.update(actor.id.encode())
|
h.update(actor.id.encode())
|
||||||
|
@ -91,6 +91,12 @@ def _actor_hash(actor: ap.ActivityType) -> str:
|
||||||
h.update(key.key_id().encode())
|
h.update(key.key_id().encode())
|
||||||
if isinstance(actor.icon, dict) and "url" in actor.icon:
|
if isinstance(actor.icon, dict) and "url" in actor.icon:
|
||||||
h.update(actor.icon["url"].encode())
|
h.update(actor.icon["url"].encode())
|
||||||
|
if local:
|
||||||
|
# The local hash helps us detect when to send an Update
|
||||||
|
for item in actor.attachment:
|
||||||
|
h.update(item["name"].encode())
|
||||||
|
h.update(item["value"].encode())
|
||||||
|
h.update(("1" if actor.manuallyApprovesFollowers else "0").encode())
|
||||||
return h.hexdigest()
|
return h.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ from typing import Set
|
||||||
from little_boxes import activitypub as ap
|
from little_boxes import activitypub as ap
|
||||||
from poussetaches import PousseTaches
|
from poussetaches import PousseTaches
|
||||||
|
|
||||||
from config import MEDIA_CACHE
|
|
||||||
from config import DISABLE_WEBMENTIONS
|
from config import DISABLE_WEBMENTIONS
|
||||||
|
from config import MEDIA_CACHE
|
||||||
from utils import parse_datetime
|
from utils import parse_datetime
|
||||||
|
|
||||||
p = PousseTaches(
|
p = PousseTaches(
|
||||||
|
@ -102,6 +102,10 @@ class Tasks:
|
||||||
def finish_post_to_outbox(iri: str) -> None:
|
def finish_post_to_outbox(iri: str) -> None:
|
||||||
p.push(iri, "/task/finish_post_to_outbox")
|
p.push(iri, "/task/finish_post_to_outbox")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def send_actor_update() -> None:
|
||||||
|
p.push({}, "/task/send_actor_update", delay=2)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def update_question_outbox(iri: str, open_for: int) -> None:
|
def update_question_outbox(iri: str, open_for: int) -> None:
|
||||||
p.push(
|
p.push(
|
||||||
|
|
|
@ -11,6 +11,16 @@
|
||||||
|
|
||||||
<div class="p-note summary">
|
<div class="p-note summary">
|
||||||
{{ config.SUMMARY | safe }}
|
{{ config.SUMMARY | safe }}
|
||||||
|
|
||||||
|
{% if config.PROFILE_METADATA %}
|
||||||
|
<dl>
|
||||||
|
{% for item in config.ME.attachment %}
|
||||||
|
{% if item.type == "PropertyValue" %}
|
||||||
|
<dt>{{item.name | safe }}</dt><dd>{{ item.value | safe }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</dl>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
width: 25px;
|
width: 25px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
}
|
}
|
||||||
|
dt:after {content: ": ";}
|
||||||
|
dt, dd { font-size: 0.9em; }
|
||||||
{{ highlight_css }}
|
{{ highlight_css }}
|
||||||
</style>
|
</style>
|
||||||
{% block header %}{% endblock %}
|
{% block header %}{% endblock %}
|
||||||
|
|
Loading…
Reference in a new issue