Fix caching and tweak design

This commit is contained in:
Thomas Sileo 2019-07-05 22:05:28 +02:00
parent 8aba17f742
commit 98a2f8dbf8
9 changed files with 82 additions and 51 deletions

View file

@ -569,6 +569,7 @@ class MicroblogPubBackend(Backend):
) )
return None return None
print(f"processing {create!r} and incrementing {in_reply_to}")
creply = DB.activities.find_one_and_update( creply = DB.activities.find_one_and_update(
{"activity.object.id": in_reply_to}, {"activity.object.id": in_reply_to},
{"$inc": {"meta.count_reply": 1, "meta.count_direct_reply": 1}}, {"$inc": {"meta.count_reply": 1, "meta.count_direct_reply": 1}},

33
app.py
View file

@ -2639,6 +2639,7 @@ def post_to_inbox(activity: ap.BaseActivity) -> None:
if back.inbox_check_duplicate(MY_PERSON, activity.id): if back.inbox_check_duplicate(MY_PERSON, activity.id):
# The activity is already in the inbox # The activity is already in the inbox
app.logger.info(f"received duplicate activity {activity!r}, dropping it") app.logger.info(f"received duplicate activity {activity!r}, dropping it")
return
back.save(Box.INBOX, activity) back.save(Box.INBOX, activity)
Tasks.process_new_activity(activity.id) Tasks.process_new_activity(activity.id)
@ -2691,16 +2692,23 @@ def task_cache_attachments():
if actor.icon: if actor.icon:
MEDIA_CACHE.cache(actor.icon["url"], Kind.ACTOR_ICON) MEDIA_CACHE.cache(actor.icon["url"], Kind.ACTOR_ICON)
obj = None
if activity.has_type(ap.ActivityType.CREATE): if activity.has_type(ap.ActivityType.CREATE):
for attachment in activity.get_object()._data.get("attachment", []): # This means a `Create` triggered the task
if ( obj = activity.get_object()
attachment.get("mediaType", "").startswith("image/") elif activity.has_type(ap.CREATE_TYPES):
or attachment.get("type") == ap.ActivityType.IMAGE.value # This means a `Announce` triggered the task
): obj = activity
try: else:
MEDIA_CACHE.cache_attachment2(attachment["url"], iri) app.logger.warning(f"Don't know what to do with {activity!r}")
except ValueError: return
app.logger.exception(f"failed to cache {attachment}")
# Iter the attachments
for attachment in obj._data.get("attachment", []):
try:
MEDIA_CACHE.cache_attachment2(attachment, iri)
except ValueError:
app.logger.exception(f"failed to cache {attachment}")
app.logger.info(f"attachments cached for {iri}") app.logger.info(f"attachments cached for {iri}")
@ -2725,6 +2733,7 @@ def task_cache_actor() -> str:
activity = ap.fetch_remote_activity(iri) activity = ap.fetch_remote_activity(iri)
app.logger.info(f"activity={activity!r}") app.logger.info(f"activity={activity!r}")
# FIXME(tsileo): OG meta for Announce?
if activity.has_type(ap.ActivityType.CREATE): if activity.has_type(ap.ActivityType.CREATE):
Tasks.fetch_og_meta(iri) Tasks.fetch_og_meta(iri)
@ -2766,6 +2775,10 @@ def task_cache_actor() -> str:
app.logger.info(f"actor cached for {iri}") app.logger.info(f"actor cached for {iri}")
if also_cache_attachments and activity.has_type(ap.ActivityType.CREATE): if also_cache_attachments and activity.has_type(ap.ActivityType.CREATE):
Tasks.cache_attachments(iri) Tasks.cache_attachments(iri)
elif also_cache_attachments and activity.has_type(ap.ActivityType.ANNOUNCE):
obj = activity.get_object()
Tasks.cache_attachments(obj.id)
Tasks.cache_actor(obj.id)
except (ActivityGoneError, ActivityNotFoundError): except (ActivityGoneError, ActivityNotFoundError):
DB.activities.update_one({"remote_id": iri}, {"$set": {"meta.deleted": True}}) DB.activities.update_one({"remote_id": iri}, {"$set": {"meta.deleted": True}})
@ -3201,6 +3214,8 @@ def task_cleanup_part_2():
MEDIA_CACHE.fs.delete(grid_item._id) MEDIA_CACHE.fs.delete(grid_item._id)
DB.activities.delete_one({"_id": data["_id"]}) DB.activities.delete_one({"_id": data["_id"]})
# FIXME(tsileo): cleanup cache from announces object
p.push({}, "/task/cleanup_part_3") p.push({}, "/task/cleanup_part_3")
return "OK" return "OK"

View file

@ -246,6 +246,7 @@ a:hover {
color: $color-light; color: $color-light;
margin-right:5px; margin-right:5px;
border-radius:2px; border-radius:2px;
float: left;
} }
.bar-item-no-hover:hover { .bar-item-no-hover:hover {
cursor: default; cursor: default;

View file

@ -10,7 +10,7 @@
<div id="following"> <div id="following">
{% for (follow_id, follow) in following_data %} {% for (follow_id, follow) in following_data %}
{% if session.logged_in %} {% if session.logged_in %}
<div style="margin-left:90px;padding-bottom:5px;margin-bottom:15px;"> <div style="margin-left:90px;padding-bottom:5px;margin-bottom:15px;display:inline-block;">
<form action="/api/undo" class="action-form" method="POST"> <form action="/api/undo" class="action-form" method="POST">
<input type="hidden" name="redirect" value="{{ request.path }}"/> <input type="hidden" name="redirect" value="{{ request.path }}"/>
<input type="hidden" name="id" value="{{ follow_id }}"/> <input type="hidden" name="id" value="{{ follow_id }}"/>

View file

@ -37,17 +37,17 @@
{% if "actor" in item.meta %} {% if "actor" in item.meta %}
{% set boost_actor = item.meta.actor %} {% set boost_actor = item.meta.actor %}
{% if session.logged_in %} {% if session.logged_in %}
<div style="margin-left:65px;padding-bottom:5px;margin-bottom:15px;"> <div style="margin-left:65px;padding-bottom:5px;margin-bottom:15px;display:inline-block">
<span class="bar-item-no-hover"><a style="color:#808080;" href="{{ boost_actor.url | get_url }}">{{ boost_actor.name }}</a> boosted</span>
<form action="/api/undo" class="action-form" method="POST"> <form action="/api/undo" class="action-form" method="POST">
<input type="hidden" name="redirect" value="/"/> <input type="hidden" name="redirect" value="/"/>
<input type="hidden" name="id" value="{{ item.remote_id }}"/> <input type="hidden" name="id" value="{{ item.remote_id }}"/>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<button type="submit" class="bar-item">unboost</button> <button type="submit" class="bar-item">unboost</button>
</form> </form>
<span class="bar-item-no-hover"><a style="color:#808080;" href="{{ boost_actor.url | get_url }}">{{ boost_actor.name }}</a> boosted</span>
</div> </div>
{% else %} {% else %}
<p style="margin-left:65px;padding-bottom:5px;"> <p style="margin-left:65px;padding-bottom:5px;display:inline-block;">
<span class="bar-item-no-hover"><a style="color:#808080;" href="{{ boost_actor.url | get_url }}">{{ boost_actor.name }}</a> boosted</span> <span class="bar-item-no-hover"><a style="color:#808080;" href="{{ boost_actor.url | get_url }}">{{ boost_actor.name }}</a> boosted</span>
</p> </p>
{% endif %} {% endif %}

View file

@ -9,7 +9,7 @@
<div id="notes"> <div id="notes">
{% for item in liked %} {% for item in liked %}
{% if session.logged_in %} {% if session.logged_in %}
<div style="margin-left:65px;padding-bottom:5px;margin-bottom:15px;"> <div style="margin-left:65px;padding-bottom:5px;margin-bottom:15px;display:inline-block;">
<form action="/api/undo" class="action-form" method="POST"> <form action="/api/undo" class="action-form" method="POST">
<input type="hidden" name="redirect" value="/liked"/> <input type="hidden" name="redirect" value="/liked"/>
<input type="hidden" name="id" value="{{ item.remote_id }}"/> <input type="hidden" name="id" value="{{ item.remote_id }}"/>

View file

@ -16,7 +16,7 @@
{% set data = data.to_dict() %} {% set data = data.to_dict() %}
<div id="lookup-result" style="margin-top:30px;"> <div id="lookup-result" style="margin-top:30px;">
{% if data | has_actor_type %} {% if data | has_actor_type %}
<div style="margin-left:95px;padding-bottom:5px;margin-bottom:15px;"> <div style="margin-left:95px;padding-bottom:5px;margin-bottom:15px;display:inline-block;">
<form action="/api/follow" class="action-form" method="POST"> <form action="/api/follow" class="action-form" method="POST">
<input type="hidden" name="redirect" value="{{ request.path }}"/> <input type="hidden" name="redirect" value="{{ request.path }}"/>
<input type="hidden" name="actor" value="{{ data.id }}"/> <input type="hidden" name="actor" value="{{ data.id }}"/>

View file

@ -15,7 +15,7 @@
{% if item | has_type('Announce') %} {% if item | has_type('Announce') %}
{% set boost_actor = item.meta.actor %} {% set boost_actor = item.meta.actor %}
{% if boost_actor %} {% if boost_actor %}
<p style="margin-left:70px;padding-bottom:5px;"><span class="bar-item-no-hover"><a style="color:#808080;" href="{{ boost_actor.url | get_url }}">{{ boost_actor.name or boost_actor.preferredUsername }}</a> boosted</span></p> <p style="margin-left:70px;padding-bottom:5px;display:inline-block;"><span class="bar-item-no-hover"><a style="color:#808080;" href="{{ boost_actor.url | get_url }}">{{ boost_actor.name or boost_actor.preferredUsername }}</a> boosted</span></p>
{% endif %} {% endif %}
{% if item.meta.object %} {% if item.meta.object %}
{{ utils.display_note(item.meta.object, ui=True) }} {{ utils.display_note(item.meta.object, ui=True) }}
@ -24,26 +24,26 @@
{% if item | has_type('Like') %} {% if item | has_type('Like') %}
{% set boost_actor = item.meta.actor %} {% set boost_actor = item.meta.actor %}
<p style="margin-left:70px;padding-bottom:5px;"><span class="bar-item-no-hover"><a style="color:#808080;" href="{{ boost_actor.url | get_url }}">{{ boost_actor.name or boost_actor.preferredUsername }}</a> liked</span></p> <p style="margin-left:70px;padding-bottom:5px;display:inline-block;"><span class="bar-item-no-hover"><a style="color:#808080;" href="{{ boost_actor.url | get_url }}">{{ boost_actor.name or boost_actor.preferredUsername }}</a> liked</span></p>
{% if item.meta.object %} {% if item.meta.object %}
{{ utils.display_note(item.meta.object, ui=False, meta={'actor': item.meta.object_actor}) }} {{ utils.display_note(item.meta.object, ui=False, meta={'actor': item.meta.object_actor}) }}
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if item | has_type('Follow') %} {% if item | has_type('Follow') %}
<p style="margin-left:70px;padding-bottom:5px;"><span class="bar-item-no-hover">new follower</span> <!-- <a href="" class="bar-item">follow back</a></p> --> <p style="margin-left:70px;padding-bottom:5px;display:inline-block;"><span class="bar-item-no-hover">new follower</span> <!-- <a href="" class="bar-item">follow back</a></p> -->
<div style="height: 100px;"> <div style="height: 100px;">
{{ utils.display_actor_inline(item.meta.actor, size=50) }} {{ utils.display_actor_inline(item.meta.actor, size=50) }}
</div> </div>
{% elif item | has_type('Accept') %} {% elif item | has_type('Accept') %}
<p style="margin-left:70px;padding-bottom:5px;"><span class="bar-item-no-hover">you started following</span></p> <p style="margin-left:70px;padding-bottom:5px;display:inline-block;"><span class="bar-item-no-hover">you started following</span></p>
<div style="height: 100px;"> <div style="height: 100px;">
{{ utils.display_actor_inline(item.meta.actor, size=50) }} {{ utils.display_actor_inline(item.meta.actor, size=50) }}
</div> </div>
{% elif item | has_type('Undo') %} {% elif item | has_type('Undo') %}
<p style="margin-left:70px;padding-bottom:5px;"><span class="bar-item-no-hover">unfollowed you</span></p> <p style="margin-left:70px;padding-bottom:5px;display:inline-block;"><span class="bar-item-no-hover">unfollowed you</span></p>
<div style="height: 100px;"> <div style="height: 100px;">
{{ utils.display_actor_inline(item.meta.actor, size=50) }} {{ utils.display_actor_inline(item.meta.actor, size=50) }}
</div> </div>
@ -57,7 +57,7 @@
{% else %} {% else %}
{% if item | has_type('question_ended') %} {% if item | has_type('question_ended') %}
<p style="margin-left:70px;padding-bottom:5px;"><span class="bar-item-no-hover">poll ended</span></p> <p style="margin-left:70px;padding-bottom:5px;display:inline-block;"><span class="bar-item-no-hover">poll ended</span></p>
{{ utils.display_note(item.activity.object) }} {{ utils.display_note(item.activity.object) }}
{% endif %} {% endif %}

View file

@ -4,6 +4,9 @@ from enum import Enum
from gzip import GzipFile from gzip import GzipFile
from io import BytesIO from io import BytesIO
from typing import Any from typing import Any
from typing import Dict
from little_boxes import activitypub as ap
import gridfs import gridfs
import piexif import piexif
@ -115,45 +118,56 @@ class MediaCache(object):
) )
return return
def cache_attachment2(self, url: str, remote_id: str) -> None: def cache_attachment2(self, attachment: Dict[str, Any], remote_id: str) -> None:
url = attachment["url"]
# Ensure it's not already there
if self.fs.find_one({"url": url, "kind": Kind.ATTACHMENT.value}): if self.fs.find_one({"url": url, "kind": Kind.ATTACHMENT.value}):
return return
# If it's an image, make some thumbnails
if ( if (
url.endswith(".png") url.endswith(".png")
or url.endswith(".jpg") or url.endswith(".jpg")
or url.endswith(".jpeg") or url.endswith(".jpeg")
or url.endswith(".gif") or url.endswith(".gif")
or attachment.get("mediaType", "").startswith("image/")
or ap._has_type(attachment.get("type"), ap.ActivityType.IMAGE)
): ):
i = load(url, self.user_agent) try:
# Save the original attachment (gzipped) i = load(url, self.user_agent)
with BytesIO() as buf: # Save the original attachment (gzipped)
f1 = GzipFile(mode="wb", fileobj=buf) with BytesIO() as buf:
i.save(f1, format=i.format) f1 = GzipFile(mode="wb", fileobj=buf)
f1.close()
buf.seek(0)
self.fs.put(
buf,
url=url,
size=None,
content_type=i.get_format_mimetype(),
kind=Kind.ATTACHMENT.value,
remote_id=remote_id,
)
# Save a thumbnail (gzipped)
i.thumbnail((720, 720))
with BytesIO() as buf:
with GzipFile(mode="wb", fileobj=buf) as f1:
i.save(f1, format=i.format) i.save(f1, format=i.format)
buf.seek(0) f1.close()
self.fs.put( buf.seek(0)
buf, self.fs.put(
url=url, buf,
size=720, url=url,
content_type=i.get_format_mimetype(), size=None,
kind=Kind.ATTACHMENT.value, content_type=i.get_format_mimetype(),
remote_id=remote_id, kind=Kind.ATTACHMENT.value,
) remote_id=remote_id,
return )
# Save a thumbnail (gzipped)
i.thumbnail((720, 720))
with BytesIO() as buf:
with GzipFile(mode="wb", fileobj=buf) as f1:
i.save(f1, format=i.format)
buf.seek(0)
self.fs.put(
buf,
url=url,
size=720,
content_type=i.get_format_mimetype(),
kind=Kind.ATTACHMENT.value,
remote_id=remote_id,
)
return
except Exception:
# FIXME(tsileo): logging
pass
# The attachment is not an image, download and save it anyway # The attachment is not an image, download and save it anyway
with requests.get( with requests.get(