index posts edited/created from Mastodon API

This commit is contained in:
Your Name 2024-12-30 15:34:18 -05:00 committed by Henri Dickson
parent 0af7032282
commit 71cfe74f9f
7 changed files with 61 additions and 23 deletions

View file

@ -118,8 +118,8 @@ class Index:
def delete_collection(self):
self.write_collection.delete()
def update_schema(self):
self.write_collection.update(self.get_schema())
def update_schema(self, schema: dict):
self.write_collection.update(schema)
def initialize_collection(self, max_wait=5) -> bool:
try:

View file

@ -157,8 +157,8 @@ class Command(BaseCommand):
self.stdout.write(self.style.SUCCESS("deleted."))
case "idx-alt":
index.update_schema()
self.stdout.write(self.style.SUCCESS("updated."))
# index.update_schema()
self.stdout.write(self.style.SUCCESS("not implemented."))
case "idx-init":
index.initialize_collection()

View file

@ -137,12 +137,14 @@ class JournalIndex(Index):
"type": "string[]",
"locale": "zh",
"optional": True,
# "store": False,
},
{
"name": "content",
"type": "string[]",
"locale": "zh",
"optional": True,
# "store": False,
},
{
"name": "shelf_type",
@ -264,6 +266,10 @@ class JournalIndex(Index):
def delete_by_post(self, post_ids):
return self.delete_docs("post_id", post_ids)
def replace_posts(self, posts: Iterable[Post]):
docs = self.posts_to_docs(posts)
self.replace_docs(docs)
def replace_pieces(self, pieces: "Iterable[Piece] | QuerySet[Piece]"):
if isinstance(pieces, QuerySet):
pids = pieces.values_list("pk", flat=True)

@ -1 +1 @@
Subproject commit df6f939a73512ac8a8c01e0e78bc0d5e8ffe3e6d
Subproject commit 616e91382829866531c62e1b24f0e6e4595ab27d

View file

@ -125,7 +125,7 @@
{% if forloop.last %}
<div class="htmx-indicator"
style="margin-left: 60px"
{% if request.GET.q %} hx-get="{% url 'social:data' %}?q={{ request.GET.q }}&amp;page={{ nextpage }}" {% else %} hx-get="{% url 'social:data' %}?last={{ event.pk }}&amp;typ={{ feed_type }}" {% endif %}
{% if request.GET.q %} hx-get="{% url 'social:data' %}?q={{ request.GET.q }}&amp;lastpage={{ page }}" {% else %} hx-get="{% url 'social:data' %}?last={{ event.pk }}&amp;typ={{ feed_type }}" {% endif %}
hx-trigger="revealed"
hx-swap="outerHTML">
<i class="fa-solid fa-compact-disc fa-spin loading"></i>
@ -133,7 +133,7 @@
{% endif %}
{% empty %}
<div class="empty">
{% if request.GET.last or request.GET.nextpage %}
{% if request.GET.last or page > 1 %}
{% trans 'nothing more.' %}
{% elif request.GET.q %}
{% trans 'no matching activities.' %}

View file

@ -78,7 +78,7 @@ def data(request):
typ = int_(request.GET.get("typ", 0))
q = request.GET.get("q")
identity_id = request.user.identity.pk
page = int_(request.GET.get("page", 1))
page = int_(request.GET.get("lastpage")) + 1
if q:
q = QueryParser(request.GET.get("q", default=""))
index = JournalIndex.instance()
@ -149,7 +149,7 @@ def data(request):
return render(
request,
"feed_events.html",
{"feed_type": typ, "events": events, "nextpage": page + 1},
{"feed_type": typ, "events": events, "page": page},
)

View file

@ -14,6 +14,7 @@ from journal.models import (
Review,
ShelfMember,
)
from journal.models.index import JournalIndex
from users.middlewares import activate_language_for_user
from users.models.apidentity import APIdentity
@ -92,30 +93,61 @@ def _get_or_create_item(item_obj) -> Item | None:
def post_created(pk, post_data):
return post_fetched(pk, post_data)
return _post_fetched(pk, True, post_data)
def post_edited(pk, post_data):
return post_fetched(pk, post_data)
return _post_fetched(pk, True, post_data, False)
def post_fetched(pk, post_data):
post = Post.objects.get(pk=pk)
return _post_fetched(pk, False, post_data, True)
def _post_fetched(pk, local, post_data, create: bool | None = None):
post: Post = Post.objects.get(pk=pk)
owner = Takahe.get_or_create_remote_apidentity(post.author)
activate_language_for_user(owner.user)
if not post.type_data and not post_data:
logger.warning(f"Post {post} has no type_data")
return
ap_objects = post_data or post.type_data.get("object", {})
items = _parse_items(ap_objects.get("tag"))
pieces = _parse_piece_objects(ap_objects.get("relatedWith"))
logger.info(f"Post {post} has items {items} and pieces {pieces}")
if local:
activate_language_for_user(owner.user)
reply_to = post.in_reply_to_post()
items = []
pieces = []
if post_data and "raw_content" in post_data:
# Local post, extract info for Note if possible
if (
reply_to
and reply_to.author_id == post.author_id
and reply_to.type_data
and "object" in reply_to.type_data
and "relatedWith" in reply_to.type_data["object"]
):
items = _parse_items(reply_to.type_data["object"].get("tag", []))
elif (
not create
and post.type_data
and "object" in post.type_data
and "relatedWith" in post.type_data["object"]
):
items = _parse_items(post.type_data["object"].get("tag", []))
pieces = [{"type": "Note", "content": post_data["raw_content"]}]
if not items or not pieces:
# Local post has no related items or usable pieces, update index and move on
JournalIndex.instance().replace_posts([post])
return
else:
if not post.type_data and not post_data:
logger.warning(f"Remote post {post} has no type_data")
return
ap_objects = post_data or post.type_data.get("object", {})
items = _parse_items(ap_objects.get("tag"))
pieces = _parse_piece_objects(ap_objects.get("relatedWith"))
if len(items) == 0:
logger.warning(f"Post {post} has no remote items")
logger.warning(f"Post {post} has no items")
return
elif len(items) > 1:
logger.warning(f"Post {post} has more than one remote item")
logger.warning(f"Post {post} has more than one item")
return
logger.info(f"Post {post} has items {items} and pieces {pieces}")
item = _get_or_create_item(items[0])
if not item:
logger.warning(f"Post {post} has no local item matched or created")
@ -128,7 +160,7 @@ def post_fetched(pk, post_data):
cls.update_by_ap_object(owner, item, p, post)
def post_deleted(pk, post_data):
def post_deleted(pk, local, post_data):
for piece in Piece.objects.filter(posts__id=pk):
if piece.local and piece.__class__ != Note:
# no delete other than Note, for backward compatibility, should reconsider later