diff --git a/compose.yml b/compose.yml
index e0604c7b..6cca442d 100644
--- a/compose.yml
+++ b/compose.yml
@@ -41,6 +41,7 @@ x-shared:
NEODB_SEARCH_URL: ${NEODB_SEARCH_URL:-typesense://user:eggplant@typesense:8108/catalog}
NEODB_EMAIL_URL:
NEODB_EMAIL_FROM: no-reply@${NEODB_SITE_DOMAIN}
+ NEODB_ENABLE_LOCAL_ONLY:
NEODB_FANOUT_LIMIT_DAYS:
TAKAHE_FANOUT_LIMIT_DAYS:
NEODB_DOWNLOADER_PROXY_LIST:
diff --git a/journal/api.py b/journal/api.py
index b77ee93e..dea01ddf 100644
--- a/journal/api.py
+++ b/journal/api.py
@@ -204,7 +204,7 @@ def review_item(request, item_uuid: str, review: ReviewInSchema):
created_time=review.created_time,
)
if post and review.post_to_fediverse:
- if settings.FORCE_CLASSIC_REPOST:
+ if request.user.preference.mastodon_repost_mode == 1:
share_review(review)
else:
boost_toot_later(request.user, post.url)
diff --git a/journal/models/mark.py b/journal/models/mark.py
index ab001a36..0dc37f17 100644
--- a/journal/models/mark.py
+++ b/journal/models/mark.py
@@ -233,15 +233,16 @@ class Mark:
self.rating_grade = rating_grade
# publish a new or updated ActivityPub post
post_as_new = shelf_type != last_shelf_type or visibility != last_visibility
+ classic_repost = self.owner.user.preference.mastodon_repost_mode == 1
append = (
f" \n@{self.owner.user.mastodon_acct}"
- if visibility > 0 and share_to_mastodon
+ if visibility > 0 and share_to_mastodon and not classic_repost
else ""
)
post = Takahe.post_mark(self, post_as_new, append)
# async boost to mastodon
if post and share_to_mastodon:
- if settings.FORCE_CLASSIC_REPOST:
+ if classic_repost:
share_mark(self)
else:
boost_toot_later(self.owner.user, post.url)
diff --git a/journal/templates/comment.html b/journal/templates/comment.html
index 5adbd1d8..9840bfc0 100644
--- a/journal/templates/comment.html
+++ b/journal/templates/comment.html
@@ -31,13 +31,15 @@
+ {% if request.user.mastodon_acct %}
+
+ 转发到主ID时间轴
+
+ {% endif %}
diff --git a/journal/templates/replies.html b/journal/templates/replies.html
index d413ea22..d5099651 100644
--- a/journal/templates/replies.html
+++ b/journal/templates/replies.html
@@ -50,8 +50,8 @@
diff --git a/journal/views/collection.py b/journal/views/collection.py
index 649e6396..df63d2cf 100644
--- a/journal/views/collection.py
+++ b/journal/views/collection.py
@@ -129,17 +129,26 @@ def collection_share(request: AuthedHttpRequest, collection_uuid):
if request.method == "GET":
return render(request, "collection_share.html", {"collection": collection})
elif request.method == "POST":
- if settings.FORCE_CLASSIC_REPOST:
- visibility = int(request.POST.get("visibility", default=0))
- comment = request.POST.get("comment")
- if share_collection(collection, comment, request.user, visibility):
- return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
- else:
- return render_relogin(request)
+ comment = request.POST.get("comment")
+ # boost if possible, otherwise quote
+ if (
+ not comment
+ and request.user.preference.mastodon_repost_mode == 0
+ and collection.latest_post
+ ):
+ boost_toot_later(request.user, collection.latest_post.url)
else:
- if collection.latest_post:
- boost_toot_later(request.user, collection.latest_post)
- return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
+ visibility = int(request.POST.get("visibility", default=0))
+ link = (
+ collection.latest_post.url
+ if collection.latest_post
+ else collection.absolute_url
+ )
+ if not share_collection(
+ collection, comment, request.user, visibility, link
+ ):
+ return render_relogin(request)
+ return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
else:
raise BadRequest()
diff --git a/journal/views/mark.py b/journal/views/mark.py
index 9f38428a..9988bff8 100644
--- a/journal/views/mark.py
+++ b/journal/views/mark.py
@@ -13,7 +13,7 @@ from django.utils.translation import gettext_lazy as _
from catalog.models import *
from common.utils import AuthedHttpRequest, PageLinksGenerator, get_uuid_or_404
-from mastodon.api import boost_toot_later
+from mastodon.api import boost_toot_later, share_comment
from takahe.utils import Takahe
from ..models import (
@@ -236,7 +236,10 @@ def comment(request: AuthedHttpRequest, item_uuid):
post = Takahe.post_comment(comment, False)
share_to_mastodon = bool(request.POST.get("share_to_mastodon", default=False))
if post and share_to_mastodon:
- boost_toot_later(request.user, post.url)
+ if request.user.preference.mastodon_repost_mode == 1:
+ share_comment(comment)
+ else:
+ boost_toot_later(request.user, post.url)
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
raise BadRequest()
diff --git a/journal/views/review.py b/journal/views/review.py
index b2316b88..83dbaa24 100644
--- a/journal/views/review.py
+++ b/journal/views/review.py
@@ -85,7 +85,7 @@ def review_edit(request: AuthedHttpRequest, item_uuid, review_uuid=None):
if not review:
raise BadRequest()
if form.cleaned_data["share_to_mastodon"] and post:
- if settings.FORCE_CLASSIC_REPOST:
+ if request.user.preference.mastodon_repost_mode == 1:
share_review(review)
else:
boost_toot_later(request.user, post.url)
diff --git a/mastodon/api.py b/mastodon/api.py
index c54dba7f..f3ed4249 100644
--- a/mastodon/api.py
+++ b/mastodon/api.py
@@ -91,7 +91,9 @@ def boost_toot(site, token, toot_url):
j = response.json()
if "statuses" in j and len(j["statuses"]) > 0:
s = j["statuses"][0]
- if s["uri"] != toot_url and s["url"] != toot_url:
+ url_id = toot_url.split("/posts/")[-1]
+ url_id2 = s["uri"].split("/posts/")[-1]
+ if s["uri"] != toot_url and s["url"] != toot_url and url_id != url_id2:
logger.warning(
f"Error status url mismatch {s['uri']} or {s['uri']} != {toot_url}"
)
@@ -437,29 +439,57 @@ def get_spoiler_text(text, item):
return None, text
-def get_visibility(visibility, user):
+def get_toot_visibility(visibility, user):
if visibility == 2:
return TootVisibilityEnum.DIRECT
elif visibility == 1:
return TootVisibilityEnum.PRIVATE
- elif user.preference.mastodon_publish_public:
+ elif user.preference.post_public_mode == 0:
return TootVisibilityEnum.PUBLIC
else:
return TootVisibilityEnum.UNLISTED
+def share_comment(comment):
+ from catalog.common import ItemCategory
+
+ user = comment.owner.user
+ visibility = get_toot_visibility(comment.visibility, user)
+ tags = (
+ "\n"
+ + user.preference.mastodon_append_tag.replace(
+ "[category]", str(ItemCategory(comment.item.category).label)
+ )
+ if user.preference.mastodon_append_tag
+ else ""
+ )
+ content = f"评论《{comment.item.display_title}》\n{comment.text}\n{comment.item.absolute_url}{tags}"
+ update_id = None
+ if comment.metadata.get(
+ "shared_link"
+ ): # "https://mastodon.social/@username/1234567890"
+ r = re.match(
+ r".+/(\w+)$", comment.metadata.get("shared_link")
+ ) # might be re.match(r'.+/([^/]+)$', u) if Pleroma supports edit
+ update_id = r[1] if r else None
+ response = post_toot(
+ user.mastodon_site, content, visibility, user.mastodon_token, False, update_id
+ )
+ if response is not None and response.status_code in [200, 201]:
+ j = response.json()
+ if "url" in j:
+ comment.metadata["shared_link"] = j["url"]
+ comment.save()
+ return True
+ else:
+ return False
+
+
def share_mark(mark):
from catalog.common import ItemCategory
user = mark.owner.user
- if mark.visibility == 2:
- visibility = TootVisibilityEnum.DIRECT
- elif mark.visibility == 1:
- visibility = TootVisibilityEnum.PRIVATE
- elif user.preference.mastodon_publish_public:
- visibility = TootVisibilityEnum.PUBLIC
- else:
- visibility = TootVisibilityEnum.UNLISTED
+ visibility = get_toot_visibility(mark.visibility, user)
tags = (
"\n"
+ user.preference.mastodon_append_tag.replace(
@@ -473,7 +503,7 @@ def share_mark(mark):
MastodonApplication.objects.get(domain_name=user.mastodon_site).star_mode,
)
content = f"{mark.action_label}《{mark.item.display_title}》{stars}\n{mark.item.absolute_url}\n{mark.comment_text or ''}{tags}"
- update_id = get_status_id_by_url(mark.shared_link)
+ update_id = None # get_status_id_by_url(mark.shared_link)
spoiler_text, content = get_spoiler_text(content, mark.item)
response = post_toot(
user.mastodon_site,
@@ -485,11 +515,11 @@ def share_mark(mark):
spoiler_text,
)
if response is not None and response.status_code in [200, 201]:
- j = response.json()
- if "url" in j:
- mark.shared_link = j["url"]
- if mark.shared_link:
- mark.save(update_fields=["shared_link"])
+ # j = response.json()
+ # if "url" in j:
+ # mark.shared_link = j["url"]
+ # if mark.shared_link:
+ # mark.save(update_fields=["shared_link"])
return True, 200
else:
logger.warning(response)
@@ -499,15 +529,8 @@ def share_mark(mark):
def share_review(review):
from catalog.common import ItemCategory
- user = review.owner
- if review.visibility == 2:
- visibility = TootVisibilityEnum.DIRECT
- elif review.visibility == 1:
- visibility = TootVisibilityEnum.PRIVATE
- elif user.preference.mastodon_publish_public:
- visibility = TootVisibilityEnum.PUBLIC
- else:
- visibility = TootVisibilityEnum.UNLISTED
+ user = review.owner.user
+ visibility = get_toot_visibility(review.visibility, user)
tags = (
"\n"
+ user.preference.mastodon_append_tag.replace(
@@ -538,15 +561,8 @@ def share_review(review):
return False
-def share_collection(collection, comment, user, visibility_no):
- if visibility_no == 2:
- visibility = TootVisibilityEnum.DIRECT
- elif visibility_no == 1:
- visibility = TootVisibilityEnum.PRIVATE
- elif user.preference.mastodon_publish_public:
- visibility = TootVisibilityEnum.PUBLIC
- else:
- visibility = TootVisibilityEnum.UNLISTED
+def share_collection(collection, comment, user, visibility_no, link):
+ visibility = get_toot_visibility(visibility_no, user)
tags = (
"\n" + user.preference.mastodon_append_tag.replace("[category]", "收藏单")
if user.preference.mastodon_append_tag
@@ -561,7 +577,7 @@ def share_collection(collection, comment, user, visibility_no):
else " " + collection.owner.username + " "
)
)
- content = f"分享{user_str}的收藏单《{collection.title}》\n{collection.absolute_url}\n{comment}{tags}"
+ content = f"分享{user_str}的收藏单《{collection.title}》\n{link}\n{comment}{tags}"
response = post_toot(user.mastodon_site, content, visibility, user.mastodon_token)
if response is not None and response.status_code in [200, 201]:
return True
diff --git a/takahe/utils.py b/takahe/utils.py
index 972fbf3e..426268d4 100644
--- a/takahe/utils.py
+++ b/takahe/utils.py
@@ -416,22 +416,26 @@ class Takahe:
PostInteraction.objects.filter(post__in=post_pks).update(state="undone")
@staticmethod
- def visibility_n2t(visibility: int, default_public) -> Visibilities:
+ def visibility_n2t(visibility: int, post_public_mode: int) -> Visibilities:
if visibility == 1:
return Takahe.Visibilities.followers
elif visibility == 2:
return Takahe.Visibilities.mentioned
- elif default_public:
- return Takahe.Visibilities.public
- else:
+ elif post_public_mode == 4:
+ return Takahe.Visibilities.local_only
+ elif post_public_mode == 1:
return Takahe.Visibilities.unlisted
+ else:
+ return Takahe.Visibilities.public
@staticmethod
def post_collection(collection: "Collection"):
existing_post = collection.latest_post
user = collection.owner.user
+ if not user:
+ raise ValueError(f"Cannot find user for collection {collection}")
visibility = Takahe.visibility_n2t(
- collection.visibility, user.preference.mastodon_publish_public
+ collection.visibility, user.preference.post_public_mode
)
if existing_post and visibility != existing_post.visibility:
Takahe.delete_posts([existing_post.pk])
@@ -490,9 +494,7 @@ class Takahe:
"relatedWith": [comment.ap_object],
}
}
- v = Takahe.visibility_n2t(
- comment.visibility, user.preference.mastodon_publish_public
- )
+ v = Takahe.visibility_n2t(comment.visibility, user.preference.post_public_mode)
existing_post = None if share_as_new_post else comment.latest_post
post = Takahe.post(
comment.owner.pk,
@@ -532,9 +534,7 @@ class Takahe:
"relatedWith": [review.ap_object],
}
}
- v = Takahe.visibility_n2t(
- review.visibility, user.preference.mastodon_publish_public
- )
+ v = Takahe.visibility_n2t(review.visibility, user.preference.post_public_mode)
existing_post = None if share_as_new_post else review.latest_post
post = Takahe.post( # TODO post as Article?
review.owner.pk,
@@ -580,9 +580,7 @@ class Takahe:
data["object"]["relatedWith"].append(mark.comment.ap_object)
if mark.rating:
data["object"]["relatedWith"].append(mark.rating.ap_object)
- v = Takahe.visibility_n2t(
- mark.visibility, user.preference.mastodon_publish_public
- )
+ v = Takahe.visibility_n2t(mark.visibility, user.preference.post_public_mode)
existing_post = (
None
if share_as_new_post
diff --git a/users/data.py b/users/data.py
index 4c6b4d31..836f4128 100644
--- a/users/data.py
+++ b/users/data.py
@@ -25,31 +25,37 @@ def preferences(request):
preference = request.user.preference
if request.method == "POST":
preference.default_visibility = int(request.POST.get("default_visibility"))
- preference.default_no_share = bool(request.POST.get("default_no_share"))
+ preference.mastodon_default_repost = (
+ int(request.POST.get("mastodon_default_repost", 0)) == 1
+ )
preference.no_anonymous_view = bool(request.POST.get("no_anonymous_view"))
preference.classic_homepage = int(request.POST.get("classic_homepage"))
preference.hidden_categories = request.POST.getlist("hidden_categories")
- preference.mastodon_publish_public = bool(
- request.POST.get("mastodon_publish_public")
- )
+ preference.post_public_mode = int(request.POST.get("post_public_mode"))
preference.show_last_edit = bool(request.POST.get("show_last_edit"))
+ preference.mastodon_repost_mode = int(request.POST.get("mastodon_repost_mode"))
preference.mastodon_append_tag = request.POST.get(
"mastodon_append_tag", ""
).strip()
preference.save(
update_fields=[
"default_visibility",
- "default_no_share",
+ "post_public_mode",
"no_anonymous_view",
"classic_homepage",
- "mastodon_publish_public",
"mastodon_append_tag",
+ "mastodon_repost_mode",
+ "mastodon_default_repost",
"show_last_edit",
"hidden_categories",
]
)
clear_preference_cache(request)
- return render(request, "users/preferences.html")
+ return render(
+ request,
+ "users/preferences.html",
+ {"enable_local_only": settings.ENABLE_LOCAL_ONLY},
+ )
@login_required
diff --git a/users/migrations/0015_remove_preference_mastodon_publish_public_and_more.py b/users/migrations/0015_remove_preference_mastodon_publish_public_and_more.py
new file mode 100644
index 00000000..b1a5c8b2
--- /dev/null
+++ b/users/migrations/0015_remove_preference_mastodon_publish_public_and_more.py
@@ -0,0 +1,42 @@
+# Generated by Django 4.2.8 on 2023-12-10 18:25
+
+from django.db import migrations, models
+
+
+def migrate_public_mode(apps, schema_editor):
+ User = apps.get_model("users", "User")
+ User.objects.filter(mastodon_publish_public=True).update(post_public_mode=0)
+ User.objects.filter(mastodon_publish_public=False).update(post_public_mode=1)
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("users", "0014_preference_mastodon_skip_relationship_and_more"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="preference",
+ name="mastodon_repost_mode",
+ field=models.PositiveSmallIntegerField(default=0),
+ ),
+ migrations.AddField(
+ model_name="preference",
+ name="post_public_mode",
+ field=models.PositiveSmallIntegerField(default=0),
+ ),
+ # migrations.RunPython(migrate_public_mode),
+ migrations.RunSQL(
+ "UPDATE users_preference SET post_public_mode = 1 where mastodon_publish_public = false;"
+ ),
+ migrations.AlterField(
+ model_name="preference",
+ name="show_last_edit",
+ field=models.PositiveSmallIntegerField(default=1),
+ ),
+ migrations.RemoveField(
+ model_name="preference",
+ name="mastodon_publish_public",
+ ),
+ ]
diff --git a/users/migrations/0016_rename_preference_default_no_share.py b/users/migrations/0016_rename_preference_default_no_share.py
new file mode 100644
index 00000000..112504ad
--- /dev/null
+++ b/users/migrations/0016_rename_preference_default_no_share.py
@@ -0,0 +1,25 @@
+# Generated by Django 4.2.8 on 2023-12-10 19:26
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("users", "0015_remove_preference_mastodon_publish_public_and_more"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="preference",
+ name="mastodon_default_repost",
+ field=models.BooleanField(default=True),
+ ),
+ migrations.RunSQL(
+ "UPDATE users_preference SET mastodon_default_repost = false where default_no_share = true;"
+ ),
+ migrations.RemoveField(
+ model_name="preference",
+ name="default_no_share",
+ ),
+ ]
diff --git a/users/models/preference.py b/users/models/preference.py
index 3b9e2c86..50b8c4ec 100644
--- a/users/models/preference.py
+++ b/users/models/preference.py
@@ -40,16 +40,23 @@ class Preference(models.Model):
import_status = models.JSONField(
blank=True, null=True, encoder=DjangoJSONEncoder, default=dict
)
- default_no_share = models.BooleanField(default=False)
- default_visibility = models.PositiveSmallIntegerField(default=0)
+ # 0: public, 1: follower only, 2: private
+ default_visibility = models.PositiveSmallIntegerField(null=False, default=0)
+ # 0: public, 1: unlisted, 4: local
+ post_public_mode = models.PositiveSmallIntegerField(null=False, default=0)
+ # 0: discover, 1: timeline, 2: my profile
classic_homepage = models.PositiveSmallIntegerField(null=False, default=0)
- mastodon_publish_public = models.BooleanField(null=False, default=False)
- mastodon_append_tag = models.CharField(max_length=2048, default="")
- show_last_edit = models.PositiveSmallIntegerField(default=0)
+ show_last_edit = models.PositiveSmallIntegerField(null=False, default=1)
no_anonymous_view = models.PositiveSmallIntegerField(default=0)
hidden_categories = models.JSONField(default=list)
+ mastodon_append_tag = models.CharField(max_length=2048, default="")
+ mastodon_default_repost = models.BooleanField(null=False, default=True)
+ mastodon_repost_mode = models.PositiveSmallIntegerField(null=False, default=0)
mastodon_skip_userinfo = models.BooleanField(null=False, default=False)
mastodon_skip_relationship = models.BooleanField(null=False, default=False)
+ # Removed:
+ # mastodon_publish_public = models.BooleanField(null=False, default=False)
+ # default_no_share = models.BooleanField(null=False, default=False)
def __str__(self):
return str(self.user)
diff --git a/users/templates/users/preferences.html b/users/templates/users/preferences.html
index ca8c30a0..e5529231 100644
--- a/users/templates/users/preferences.html
+++ b/users/templates/users/preferences.html
@@ -26,7 +26,7 @@