pin a hashtag
This commit is contained in:
parent
a20779ce31
commit
432b435083
13 changed files with 313 additions and 154 deletions
|
@ -78,11 +78,11 @@ dialog {
|
||||||
.grid>div:nth-child(2) fieldset {
|
.grid>div:nth-child(2) fieldset {
|
||||||
float: unset;
|
float: unset;
|
||||||
}
|
}
|
||||||
|
.grid {
|
||||||
|
grid-row-gap: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
article {
|
article {
|
||||||
padding-bottom: 1em;
|
padding-bottom: 1em;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
h1, h2, h3, h4, h5, h6 {
|
h1, h2, h3, h4, h5 {
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
<img src="{{ identity.avatar|relative_uri }}" alt="">
|
<img src="{{ identity.avatar|relative_uri }}" alt="">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div style="align-content:center;">
|
||||||
<hgroup>
|
<hgroup>
|
||||||
<h6 class="nickname">{{ identity.display_name }}</h6>
|
<h6 class="nickname">{{ identity.display_name }}</h6>
|
||||||
<div>
|
<div>
|
||||||
|
@ -68,9 +68,10 @@
|
||||||
{% include 'users/profile_actions.html' %}
|
{% include 'users/profile_actions.html' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
<p>
|
<div>
|
||||||
{{ identity.summary|bleach:"a,p,span,br"|default:"<br>" }}
|
{{ identity.summary|bleach:"a,p,span,br"|default:"" }}
|
||||||
</p>
|
<br>
|
||||||
|
</div>
|
||||||
</details>
|
</details>
|
||||||
</article>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
|
|
17
journal/migrations/0025_pin_tags.py
Normal file
17
journal/migrations/0025_pin_tags.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# Generated by Django 4.2.13 on 2024-06-04 19:29
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("journal", "0024_i18n"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="tag",
|
||||||
|
name="pinned",
|
||||||
|
field=models.BooleanField(default=False, null=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -47,8 +47,7 @@ class Tag(List):
|
||||||
title = models.CharField(
|
title = models.CharField(
|
||||||
max_length=100, null=False, blank=False, validators=TagValidators
|
max_length=100, null=False, blank=False, validators=TagValidators
|
||||||
)
|
)
|
||||||
# TODO case convert and space removal on save
|
pinned = models.BooleanField(default=False, null=True)
|
||||||
# TODO check on save
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = [["owner", "title"]]
|
unique_together = [["owner", "title"]]
|
||||||
|
@ -61,7 +60,27 @@ class Tag(List):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def deep_cleanup_title(title):
|
def deep_cleanup_title(title):
|
||||||
"""Remove all non-word characters, only for public index purpose"""
|
"""Remove all non-word characters, only for public index purpose"""
|
||||||
return re.sub(r"\W+", " ", title).rstrip().lstrip("# ").lower() or "_"
|
return re.sub(r"\W+", " ", title).rstrip().lstrip("# ").lower()[:100] or "_"
|
||||||
|
|
||||||
|
def update(
|
||||||
|
self, title: str, visibility: int | None = None, pinned: bool | None = None
|
||||||
|
):
|
||||||
|
old_title = Tag.deep_cleanup_title(self.title)
|
||||||
|
new_title = Tag.deep_cleanup_title(title)
|
||||||
|
was_pinned = bool(self.pinned)
|
||||||
|
if visibility is not None:
|
||||||
|
self.visibility = 2 if visibility else 0
|
||||||
|
if pinned is not None:
|
||||||
|
self.pinned = pinned
|
||||||
|
self.title = title
|
||||||
|
self.save()
|
||||||
|
if was_pinned != self.pinned or (old_title != new_title and self.pinned):
|
||||||
|
from takahe.utils import Takahe
|
||||||
|
|
||||||
|
if was_pinned:
|
||||||
|
Takahe.unpin_hashtag_for_user(self.owner.pk, old_title)
|
||||||
|
if self.pinned:
|
||||||
|
Takahe.pin_hashtag_for_user(self.owner.pk, new_title)
|
||||||
|
|
||||||
|
|
||||||
class TagManager:
|
class TagManager:
|
||||||
|
|
|
@ -4,72 +4,57 @@
|
||||||
{% load humanize %}
|
{% load humanize %}
|
||||||
{% load mastodon %}
|
{% load mastodon %}
|
||||||
{% load thumb %}
|
{% load thumb %}
|
||||||
<div id="modal"
|
<dialog open
|
||||||
_="on closeModal add .closing then wait for animationend then remove me">
|
class="tag-editor"
|
||||||
<div class="modal-underlay" _="on click trigger closeModal"></div>
|
_="on close_dialog add .closing then wait for animationend then remove me">
|
||||||
<div class="modal-content">
|
<article>
|
||||||
<div class="add-to-list-modal__head">
|
<header>
|
||||||
<span class="add-to-list-modal__title">{% trans 'Tag' %} - {{ item.title }} - {% trans 'Edit' %}</span>
|
<link to="#"
|
||||||
<span class="add-to-list-modal__close-button modal-close"
|
aria-label="Close"
|
||||||
_="on click trigger closeModal">
|
class="close"
|
||||||
<i class="fa-solid fa-xmark"></i>
|
_="on click trigger close_dialog" />
|
||||||
</span>
|
<strong>{% trans 'Edit' %} {{ tag.title }}</strong>
|
||||||
</div>
|
</header>
|
||||||
<div class="add-to-list-modal__body">
|
<div>
|
||||||
<form action="{% url 'journal:user_tag_edit' %}?tag={{ tag.title }}"
|
<form action="{% url 'journal:user_tag_edit' %}?tag={{ tag.title }}"
|
||||||
method="post">
|
method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type="hidden" name="id" value="{{ tag.id }}">
|
<input type="hidden" name="id" value="{{ tag.id }}">
|
||||||
<div class="mark-modal__tag">
|
<input name="title" type="text" value="{{ tag.title }}" required>
|
||||||
<div class="tag-input">
|
<fieldset>
|
||||||
<input name="title" type="text" value="{{ tag.title }}" required>
|
<label for="_pinned">
|
||||||
</div>
|
<input role="switch"
|
||||||
</div>
|
type="checkbox"
|
||||||
<div class="mark-modal__option">
|
name="pinned"
|
||||||
<div class="mark-modal__visibility-radio">
|
value="1"
|
||||||
<span>{% trans "Visibility" %}
|
{% if tag.pinned %}checked{% endif %}
|
||||||
<ul id="id_visibility">
|
id="_pinned">
|
||||||
<li>
|
{% trans "Pin" %}
|
||||||
<label for="id_visibility_0">
|
</label>
|
||||||
<input type="radio"
|
</fieldset>
|
||||||
name="visibility"
|
<fieldset>
|
||||||
value="0"
|
<input type="radio"
|
||||||
required=""
|
name="visibility"
|
||||||
id="id_visibility_0"
|
value="0"
|
||||||
{% if tag.visibility == 0 %}checked{% endif %}>
|
required=""
|
||||||
{% trans "Public" %}
|
id="id_visibility_0"
|
||||||
</label>
|
{% if tag.visibility == 0 %}checked{% endif %}>
|
||||||
</li>
|
<label for="id_visibility_0">{% trans "Public" %}</label>
|
||||||
<li>
|
<input type="radio"
|
||||||
<label for="id_visibility_2">
|
name="visibility"
|
||||||
<input type="radio"
|
value="2"
|
||||||
name="visibility"
|
required=""
|
||||||
value="2"
|
id="id_visibility_2"
|
||||||
required=""
|
{% if tag.visibility != 0 %}checked{% endif %}>
|
||||||
id="id_visibility_2"
|
<label for="id_visibility_2">{% trans "Personal" %}</label>
|
||||||
{% if tag.visibility != 0 %}checked{% endif %}>
|
</fieldset>
|
||||||
{% trans "Personal" %}
|
<input type="submit" class="button float-right" value="{% trans "Save" %}">
|
||||||
</label>
|
<small>{% trans "Personal tags are not shown to others when they view your tag list, unless you pin them. However, if you use this tag when marking an item publicly, it might still be visible to others." %}</small>
|
||||||
</li>
|
<label for="_delete">
|
||||||
</ul>
|
<input type="checkbox" name="delete" value="1" id="_delete">
|
||||||
</span>
|
{% trans "Delete this tag" %}
|
||||||
</div>
|
</label>
|
||||||
<i>{% trans "Personal tags are not shown to others when they view your tag list. However, if you use this tag when marking an item publicly, it might still be visible to others." %}</i>
|
|
||||||
</div>
|
|
||||||
<div class="mark-modal__confirm-button">
|
|
||||||
<input type="submit" class="button float-right" value="{% trans "Save" %}">
|
|
||||||
</div>
|
|
||||||
<div class="mark-modal__option">
|
|
||||||
<div class="mark-modal__visibility-radio">
|
|
||||||
<span>
|
|
||||||
<label for="_delete">
|
|
||||||
<input type="checkbox" name="delete" value="1" id="_delete">
|
|
||||||
{% trans "Delete this tag" %}
|
|
||||||
</label>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</article>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
{% include "_header.html" %}
|
{% include "_header.html" %}
|
||||||
<main>
|
<main>
|
||||||
<div class="grid__main">
|
<div class="grid__main">
|
||||||
<h5 class="large-only">
|
<h5>
|
||||||
{% block head %}{{ identity.display_name }}{% endblock %}
|
{% block head %}{{ identity.display_name }}{% endblock %}
|
||||||
</h5>
|
</h5>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -68,10 +68,11 @@ def user_tag_edit(request):
|
||||||
):
|
):
|
||||||
msg.error(request.user, _("Duplicated tag."))
|
msg.error(request.user, _("Duplicated tag."))
|
||||||
return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
|
return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
|
||||||
tag.title = tag_title
|
tag.update(
|
||||||
tag.visibility = int(request.POST.get("visibility", 0))
|
tag_title,
|
||||||
tag.visibility = 0 if tag.visibility == 0 else 2
|
int(request.POST.get("visibility", 0)),
|
||||||
tag.save()
|
bool(request.POST.get("pinned", 0)),
|
||||||
|
)
|
||||||
msg.info(request.user, _("Tag updated."))
|
msg.info(request.user, _("Tag updated."))
|
||||||
return redirect(
|
return redirect(
|
||||||
reverse(
|
reverse(
|
||||||
|
|
|
@ -6,7 +6,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-06-04 10:15-0400\n"
|
"POT-Creation-Date: 2024-06-04 16:48-0400\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -667,7 +667,7 @@ msgstr "不再提示"
|
||||||
#: catalog/templates/_item_comments_by_episode.html:78
|
#: catalog/templates/_item_comments_by_episode.html:78
|
||||||
#: catalog/templates/_item_reviews.html:43
|
#: catalog/templates/_item_reviews.html:43
|
||||||
#: catalog/templates/podcast_episode_data.html:41
|
#: catalog/templates/podcast_episode_data.html:41
|
||||||
#: common/templates/_sidebar.html:203
|
#: common/templates/_sidebar.html:204
|
||||||
msgid "show more"
|
msgid "show more"
|
||||||
msgstr "显示更多"
|
msgstr "显示更多"
|
||||||
|
|
||||||
|
@ -1018,7 +1018,7 @@ msgstr "否"
|
||||||
#: journal/templates/collection.html:132
|
#: journal/templates/collection.html:132
|
||||||
#: journal/templates/collection_edit.html:9
|
#: journal/templates/collection_edit.html:9
|
||||||
#: journal/templates/collection_edit.html:25 journal/templates/review.html:80
|
#: journal/templates/collection_edit.html:25 journal/templates/review.html:80
|
||||||
#: journal/templates/tag_edit.html:12
|
#: journal/templates/tag_edit.html:16
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr "编辑"
|
msgstr "编辑"
|
||||||
|
|
||||||
|
@ -1031,7 +1031,7 @@ msgstr "创建"
|
||||||
#: journal/templates/add_to_collection.html:35
|
#: journal/templates/add_to_collection.html:35
|
||||||
#: journal/templates/collection_edit.html:38 journal/templates/comment.html:69
|
#: journal/templates/collection_edit.html:38 journal/templates/comment.html:69
|
||||||
#: journal/templates/mark.html:147 journal/templates/review_edit.html:39
|
#: journal/templates/mark.html:147 journal/templates/review_edit.html:39
|
||||||
#: journal/templates/tag_edit.html:60 users/templates/users/account.html:43
|
#: journal/templates/tag_edit.html:51 users/templates/users/account.html:43
|
||||||
#: users/templates/users/account.html:104
|
#: users/templates/users/account.html:104
|
||||||
#: users/templates/users/preferences.html:168
|
#: users/templates/users/preferences.html:168
|
||||||
#: users/templates/users/preferences.html:193
|
#: users/templates/users/preferences.html:193
|
||||||
|
@ -1112,8 +1112,8 @@ msgstr "热门标签"
|
||||||
|
|
||||||
#: catalog/templates/discover.html:185 catalog/templates/item_base.html:236
|
#: catalog/templates/discover.html:185 catalog/templates/item_base.html:236
|
||||||
#: catalog/templates/item_mark_list.html:54
|
#: catalog/templates/item_mark_list.html:54
|
||||||
#: catalog/templates/item_review_list.html:50 common/templates/_sidebar.html:98
|
#: catalog/templates/item_review_list.html:50 common/templates/_sidebar.html:99
|
||||||
#: common/templates/_sidebar.html:198
|
#: common/templates/_sidebar.html:199
|
||||||
#: common/templates/_sidebar_anonymous.html:43
|
#: common/templates/_sidebar_anonymous.html:43
|
||||||
#: common/templates/_sidebar_anonymous.html:58
|
#: common/templates/_sidebar_anonymous.html:58
|
||||||
#: journal/templates/collection_items.html:8 journal/templates/posts.html:45
|
#: journal/templates/collection_items.html:8 journal/templates/posts.html:45
|
||||||
|
@ -1544,31 +1544,31 @@ msgstr "设置用户名"
|
||||||
msgid "approving followers manually"
|
msgid "approving followers manually"
|
||||||
msgstr "已开启关注审核"
|
msgstr "已开启关注审核"
|
||||||
|
|
||||||
#: common/templates/_sidebar.html:83
|
#: common/templates/_sidebar.html:84
|
||||||
msgid "Current Targets"
|
msgid "Current Targets"
|
||||||
msgstr "当前目标"
|
msgstr "当前目标"
|
||||||
|
|
||||||
#: common/templates/_sidebar.html:96
|
#: common/templates/_sidebar.html:97
|
||||||
msgid "Set a collection as target, its progress will show up here."
|
msgid "Set a collection as target, its progress will show up here."
|
||||||
msgstr "将自己或他人的收藏单设为目标,这里就会显示进度"
|
msgstr "将自己或他人的收藏单设为目标,这里就会显示进度"
|
||||||
|
|
||||||
#: common/templates/_sidebar.html:109
|
#: common/templates/_sidebar.html:110
|
||||||
msgid "Recent podcast episodes"
|
msgid "Recent podcast episodes"
|
||||||
msgstr "近期播客节目"
|
msgstr "近期播客节目"
|
||||||
|
|
||||||
#: common/templates/_sidebar.html:144
|
#: common/templates/_sidebar.html:145
|
||||||
msgid "Currently reading"
|
msgid "Currently reading"
|
||||||
msgstr "正在阅读"
|
msgstr "正在阅读"
|
||||||
|
|
||||||
#: common/templates/_sidebar.html:167
|
#: common/templates/_sidebar.html:168
|
||||||
msgid "Currently watching"
|
msgid "Currently watching"
|
||||||
msgstr "正在追看"
|
msgstr "正在追看"
|
||||||
|
|
||||||
#: common/templates/_sidebar.html:190
|
#: common/templates/_sidebar.html:191
|
||||||
msgid "Common Tags"
|
msgid "Common Tags"
|
||||||
msgstr "常用标签"
|
msgstr "常用标签"
|
||||||
|
|
||||||
#: common/templates/_sidebar.html:214
|
#: common/templates/_sidebar.html:215
|
||||||
msgid "Recent Posts"
|
msgid "Recent Posts"
|
||||||
msgstr "近期帖文"
|
msgstr "近期帖文"
|
||||||
|
|
||||||
|
@ -1722,8 +1722,8 @@ msgstr "发布到联邦宇宙"
|
||||||
|
|
||||||
#: journal/forms.py:25 journal/forms.py:45
|
#: journal/forms.py:25 journal/forms.py:45
|
||||||
#: journal/templates/collection_share.html:24
|
#: journal/templates/collection_share.html:24
|
||||||
#: journal/templates/tag_edit.html:30 journal/templates/wrapped_share.html:36
|
#: journal/templates/wrapped_share.html:36 users/templates/users/data.html:38
|
||||||
#: users/templates/users/data.html:38 users/templates/users/data.html:130
|
#: users/templates/users/data.html:130
|
||||||
msgid "Visibility"
|
msgid "Visibility"
|
||||||
msgstr "可见性"
|
msgstr "可见性"
|
||||||
|
|
||||||
|
@ -1756,7 +1756,7 @@ msgstr "备注"
|
||||||
|
|
||||||
#: journal/models/common.py:28 journal/templates/collection_share.html:35
|
#: journal/models/common.py:28 journal/templates/collection_share.html:35
|
||||||
#: journal/templates/comment.html:35 journal/templates/mark.html:93
|
#: journal/templates/comment.html:35 journal/templates/mark.html:93
|
||||||
#: journal/templates/tag_edit.html:40 journal/templates/wrapped_share.html:43
|
#: journal/templates/tag_edit.html:42 journal/templates/wrapped_share.html:43
|
||||||
#: users/templates/users/data.html:47 users/templates/users/data.html:139
|
#: users/templates/users/data.html:47 users/templates/users/data.html:139
|
||||||
#: users/templates/users/preferences.html:54
|
#: users/templates/users/preferences.html:54
|
||||||
msgid "Public"
|
msgid "Public"
|
||||||
|
@ -2493,7 +2493,7 @@ msgstr "日历"
|
||||||
msgid "annual summary"
|
msgid "annual summary"
|
||||||
msgstr "年度小结"
|
msgstr "年度小结"
|
||||||
|
|
||||||
#: journal/templates/profile.html:131 mastodon/api.py:680
|
#: journal/templates/profile.html:131 mastodon/api.py:670
|
||||||
msgid "collection"
|
msgid "collection"
|
||||||
msgstr "收藏单"
|
msgstr "收藏单"
|
||||||
|
|
||||||
|
@ -2521,19 +2521,19 @@ msgstr "保存时将行首空格替换为全角"
|
||||||
msgid "change review date"
|
msgid "change review date"
|
||||||
msgstr "指定评论日期"
|
msgstr "指定评论日期"
|
||||||
|
|
||||||
#: journal/templates/tag_edit.html:12
|
#: journal/templates/tag_edit.html:32
|
||||||
msgid "Tag"
|
msgid "Pin"
|
||||||
msgstr "标签"
|
msgstr "置顶"
|
||||||
|
|
||||||
#: journal/templates/tag_edit.html:51
|
#: journal/templates/tag_edit.html:49
|
||||||
msgid "Personal"
|
msgid "Personal"
|
||||||
msgstr "个人"
|
msgstr "个人"
|
||||||
|
|
||||||
#: journal/templates/tag_edit.html:57
|
#: journal/templates/tag_edit.html:52
|
||||||
msgid "Personal tags are not shown to others when they view your tag list. However, if you use this tag when marking an item publicly, it might still be visible to others."
|
msgid "Personal tags are not shown to others when they view your tag list, unless you pin them. However, if you use this tag when marking an item publicly, it might still be visible to others."
|
||||||
msgstr "个人标签仅限于在个人主页的标签列表里不向他人展示,如果公开标记一个条目时使用这个标签仍会被别人看到。"
|
msgstr "个人标签不被包括在条目的公共索引中,但如果公开标记一个条目时使用这个标签仍会被别人看到。"
|
||||||
|
|
||||||
#: journal/templates/tag_edit.html:67
|
#: journal/templates/tag_edit.html:55
|
||||||
msgid "Delete this tag"
|
msgid "Delete this tag"
|
||||||
msgstr "删除这个标签"
|
msgstr "删除这个标签"
|
||||||
|
|
||||||
|
@ -2685,7 +2685,7 @@ msgstr "标签已删除"
|
||||||
msgid "Duplicated tag."
|
msgid "Duplicated tag."
|
||||||
msgstr "重复标签"
|
msgstr "重复标签"
|
||||||
|
|
||||||
#: journal/views/tag.py:75
|
#: journal/views/tag.py:76
|
||||||
msgid "Tag updated."
|
msgid "Tag updated."
|
||||||
msgstr "标签已更新"
|
msgstr "标签已更新"
|
||||||
|
|
||||||
|
@ -2698,11 +2698,11 @@ msgstr "总结已发布到时间轴"
|
||||||
msgid "regarding {item_title}, may contain spoiler or triggering content"
|
msgid "regarding {item_title}, may contain spoiler or triggering content"
|
||||||
msgstr "关于 {item_title},可能包含剧透或敏感内容"
|
msgstr "关于 {item_title},可能包含剧透或敏感内容"
|
||||||
|
|
||||||
#: mastodon/api.py:685
|
#: mastodon/api.py:675
|
||||||
msgid "shared my collection"
|
msgid "shared my collection"
|
||||||
msgstr "分享我的收藏单"
|
msgstr "分享我的收藏单"
|
||||||
|
|
||||||
#: mastodon/api.py:688
|
#: mastodon/api.py:678
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "shared {username}'s collection"
|
msgid "shared {username}'s collection"
|
||||||
msgstr "分享 {username} 的收藏单"
|
msgstr "分享 {username} 的收藏单"
|
||||||
|
@ -2964,31 +2964,31 @@ msgstr "提及"
|
||||||
msgid "follow"
|
msgid "follow"
|
||||||
msgstr "关注"
|
msgstr "关注"
|
||||||
|
|
||||||
#: takahe/models.py:427
|
#: takahe/models.py:430
|
||||||
msgid "Display Name"
|
msgid "Display Name"
|
||||||
msgstr "昵称"
|
msgstr "昵称"
|
||||||
|
|
||||||
#: takahe/models.py:429
|
#: takahe/models.py:432
|
||||||
msgid "Bio"
|
msgid "Bio"
|
||||||
msgstr "简介"
|
msgstr "简介"
|
||||||
|
|
||||||
#: takahe/models.py:431
|
#: takahe/models.py:434
|
||||||
msgid "Manually approve new followers"
|
msgid "Manually approve new followers"
|
||||||
msgstr "手工审核关注者"
|
msgstr "手工审核关注者"
|
||||||
|
|
||||||
#: takahe/models.py:435
|
#: takahe/models.py:438
|
||||||
msgid "Include profile and posts in discovery"
|
msgid "Include profile and posts in discovery"
|
||||||
msgstr "允许个人资料和帖文包含在发现中"
|
msgstr "允许个人资料和帖文包含在发现中"
|
||||||
|
|
||||||
#: takahe/models.py:438
|
#: takahe/models.py:441
|
||||||
msgid "Include posts in search results"
|
msgid "Include posts in search results"
|
||||||
msgstr "允许个人帖文包含在搜索结果中"
|
msgstr "允许个人帖文包含在搜索结果中"
|
||||||
|
|
||||||
#: takahe/models.py:456
|
#: takahe/models.py:459
|
||||||
msgid "Profile picture"
|
msgid "Profile picture"
|
||||||
msgstr "头像"
|
msgstr "头像"
|
||||||
|
|
||||||
#: takahe/models.py:463
|
#: takahe/models.py:466
|
||||||
msgid "Header picture"
|
msgid "Header picture"
|
||||||
msgstr "背景图片"
|
msgstr "背景图片"
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-06-04 10:15-0400\n"
|
"POT-Creation-Date: 2024-06-04 16:48-0400\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -667,7 +667,7 @@ msgstr "不再提示"
|
||||||
#: catalog/templates/_item_comments_by_episode.html:78
|
#: catalog/templates/_item_comments_by_episode.html:78
|
||||||
#: catalog/templates/_item_reviews.html:43
|
#: catalog/templates/_item_reviews.html:43
|
||||||
#: catalog/templates/podcast_episode_data.html:41
|
#: catalog/templates/podcast_episode_data.html:41
|
||||||
#: common/templates/_sidebar.html:203
|
#: common/templates/_sidebar.html:204
|
||||||
msgid "show more"
|
msgid "show more"
|
||||||
msgstr "顯示更多"
|
msgstr "顯示更多"
|
||||||
|
|
||||||
|
@ -1018,7 +1018,7 @@ msgstr "否"
|
||||||
#: journal/templates/collection.html:132
|
#: journal/templates/collection.html:132
|
||||||
#: journal/templates/collection_edit.html:9
|
#: journal/templates/collection_edit.html:9
|
||||||
#: journal/templates/collection_edit.html:25 journal/templates/review.html:80
|
#: journal/templates/collection_edit.html:25 journal/templates/review.html:80
|
||||||
#: journal/templates/tag_edit.html:12
|
#: journal/templates/tag_edit.html:16
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr "編輯"
|
msgstr "編輯"
|
||||||
|
|
||||||
|
@ -1031,7 +1031,7 @@ msgstr "創建"
|
||||||
#: journal/templates/add_to_collection.html:35
|
#: journal/templates/add_to_collection.html:35
|
||||||
#: journal/templates/collection_edit.html:38 journal/templates/comment.html:69
|
#: journal/templates/collection_edit.html:38 journal/templates/comment.html:69
|
||||||
#: journal/templates/mark.html:147 journal/templates/review_edit.html:39
|
#: journal/templates/mark.html:147 journal/templates/review_edit.html:39
|
||||||
#: journal/templates/tag_edit.html:60 users/templates/users/account.html:43
|
#: journal/templates/tag_edit.html:51 users/templates/users/account.html:43
|
||||||
#: users/templates/users/account.html:104
|
#: users/templates/users/account.html:104
|
||||||
#: users/templates/users/preferences.html:168
|
#: users/templates/users/preferences.html:168
|
||||||
#: users/templates/users/preferences.html:193
|
#: users/templates/users/preferences.html:193
|
||||||
|
@ -1112,8 +1112,8 @@ msgstr "熱門標籤"
|
||||||
|
|
||||||
#: catalog/templates/discover.html:185 catalog/templates/item_base.html:236
|
#: catalog/templates/discover.html:185 catalog/templates/item_base.html:236
|
||||||
#: catalog/templates/item_mark_list.html:54
|
#: catalog/templates/item_mark_list.html:54
|
||||||
#: catalog/templates/item_review_list.html:50 common/templates/_sidebar.html:98
|
#: catalog/templates/item_review_list.html:50 common/templates/_sidebar.html:99
|
||||||
#: common/templates/_sidebar.html:198
|
#: common/templates/_sidebar.html:199
|
||||||
#: common/templates/_sidebar_anonymous.html:43
|
#: common/templates/_sidebar_anonymous.html:43
|
||||||
#: common/templates/_sidebar_anonymous.html:58
|
#: common/templates/_sidebar_anonymous.html:58
|
||||||
#: journal/templates/collection_items.html:8 journal/templates/posts.html:45
|
#: journal/templates/collection_items.html:8 journal/templates/posts.html:45
|
||||||
|
@ -1544,31 +1544,31 @@ msgstr "設置用戶名"
|
||||||
msgid "approving followers manually"
|
msgid "approving followers manually"
|
||||||
msgstr "已開啓關注審覈"
|
msgstr "已開啓關注審覈"
|
||||||
|
|
||||||
#: common/templates/_sidebar.html:83
|
#: common/templates/_sidebar.html:84
|
||||||
msgid "Current Targets"
|
msgid "Current Targets"
|
||||||
msgstr "當前目標"
|
msgstr "當前目標"
|
||||||
|
|
||||||
#: common/templates/_sidebar.html:96
|
#: common/templates/_sidebar.html:97
|
||||||
msgid "Set a collection as target, its progress will show up here."
|
msgid "Set a collection as target, its progress will show up here."
|
||||||
msgstr "將自己或他人的收藏單設爲目標,這裏就會顯示進度"
|
msgstr "將自己或他人的收藏單設爲目標,這裏就會顯示進度"
|
||||||
|
|
||||||
#: common/templates/_sidebar.html:109
|
#: common/templates/_sidebar.html:110
|
||||||
msgid "Recent podcast episodes"
|
msgid "Recent podcast episodes"
|
||||||
msgstr "近期播客節目"
|
msgstr "近期播客節目"
|
||||||
|
|
||||||
#: common/templates/_sidebar.html:144
|
#: common/templates/_sidebar.html:145
|
||||||
msgid "Currently reading"
|
msgid "Currently reading"
|
||||||
msgstr "正在閱讀"
|
msgstr "正在閱讀"
|
||||||
|
|
||||||
#: common/templates/_sidebar.html:167
|
#: common/templates/_sidebar.html:168
|
||||||
msgid "Currently watching"
|
msgid "Currently watching"
|
||||||
msgstr "正在追看"
|
msgstr "正在追看"
|
||||||
|
|
||||||
#: common/templates/_sidebar.html:190
|
#: common/templates/_sidebar.html:191
|
||||||
msgid "Common Tags"
|
msgid "Common Tags"
|
||||||
msgstr "常用標籤"
|
msgstr "常用標籤"
|
||||||
|
|
||||||
#: common/templates/_sidebar.html:214
|
#: common/templates/_sidebar.html:215
|
||||||
msgid "Recent Posts"
|
msgid "Recent Posts"
|
||||||
msgstr "近期帖文"
|
msgstr "近期帖文"
|
||||||
|
|
||||||
|
@ -1722,8 +1722,8 @@ msgstr "發佈到聯邦宇宙"
|
||||||
|
|
||||||
#: journal/forms.py:25 journal/forms.py:45
|
#: journal/forms.py:25 journal/forms.py:45
|
||||||
#: journal/templates/collection_share.html:24
|
#: journal/templates/collection_share.html:24
|
||||||
#: journal/templates/tag_edit.html:30 journal/templates/wrapped_share.html:36
|
#: journal/templates/wrapped_share.html:36 users/templates/users/data.html:38
|
||||||
#: users/templates/users/data.html:38 users/templates/users/data.html:130
|
#: users/templates/users/data.html:130
|
||||||
msgid "Visibility"
|
msgid "Visibility"
|
||||||
msgstr "可見性"
|
msgstr "可見性"
|
||||||
|
|
||||||
|
@ -1756,7 +1756,7 @@ msgstr "備註"
|
||||||
|
|
||||||
#: journal/models/common.py:28 journal/templates/collection_share.html:35
|
#: journal/models/common.py:28 journal/templates/collection_share.html:35
|
||||||
#: journal/templates/comment.html:35 journal/templates/mark.html:93
|
#: journal/templates/comment.html:35 journal/templates/mark.html:93
|
||||||
#: journal/templates/tag_edit.html:40 journal/templates/wrapped_share.html:43
|
#: journal/templates/tag_edit.html:42 journal/templates/wrapped_share.html:43
|
||||||
#: users/templates/users/data.html:47 users/templates/users/data.html:139
|
#: users/templates/users/data.html:47 users/templates/users/data.html:139
|
||||||
#: users/templates/users/preferences.html:54
|
#: users/templates/users/preferences.html:54
|
||||||
msgid "Public"
|
msgid "Public"
|
||||||
|
@ -2493,7 +2493,7 @@ msgstr "日曆"
|
||||||
msgid "annual summary"
|
msgid "annual summary"
|
||||||
msgstr "年度小結"
|
msgstr "年度小結"
|
||||||
|
|
||||||
#: journal/templates/profile.html:131 mastodon/api.py:680
|
#: journal/templates/profile.html:131 mastodon/api.py:670
|
||||||
msgid "collection"
|
msgid "collection"
|
||||||
msgstr "收藏單"
|
msgstr "收藏單"
|
||||||
|
|
||||||
|
@ -2521,19 +2521,19 @@ msgstr "保存時將行首空格替換爲全角"
|
||||||
msgid "change review date"
|
msgid "change review date"
|
||||||
msgstr "指定評論日期"
|
msgstr "指定評論日期"
|
||||||
|
|
||||||
#: journal/templates/tag_edit.html:12
|
#: journal/templates/tag_edit.html:32
|
||||||
msgid "Tag"
|
msgid "Pin"
|
||||||
msgstr "標籤"
|
msgstr "置頂"
|
||||||
|
|
||||||
#: journal/templates/tag_edit.html:51
|
#: journal/templates/tag_edit.html:49
|
||||||
msgid "Personal"
|
msgid "Personal"
|
||||||
msgstr "個人"
|
msgstr "個人"
|
||||||
|
|
||||||
#: journal/templates/tag_edit.html:57
|
#: journal/templates/tag_edit.html:52
|
||||||
msgid "Personal tags are not shown to others when they view your tag list. However, if you use this tag when marking an item publicly, it might still be visible to others."
|
msgid "Personal tags are not shown to others when they view your tag list, unless you pin them. However, if you use this tag when marking an item publicly, it might still be visible to others."
|
||||||
msgstr "個人標籤僅限於在個人主頁的標籤列表裏不向他人展示,如果公開標記一個條目時使用這個標籤仍會被別人看到。"
|
msgstr "個人標籤不被包括在條目的公共索引中,但如果公開標記一個條目時使用這個標籤仍會被別人看到。"
|
||||||
|
|
||||||
#: journal/templates/tag_edit.html:67
|
#: journal/templates/tag_edit.html:55
|
||||||
msgid "Delete this tag"
|
msgid "Delete this tag"
|
||||||
msgstr "刪除這個標籤"
|
msgstr "刪除這個標籤"
|
||||||
|
|
||||||
|
@ -2685,7 +2685,7 @@ msgstr "標籤已刪除"
|
||||||
msgid "Duplicated tag."
|
msgid "Duplicated tag."
|
||||||
msgstr "重複標籤"
|
msgstr "重複標籤"
|
||||||
|
|
||||||
#: journal/views/tag.py:75
|
#: journal/views/tag.py:76
|
||||||
msgid "Tag updated."
|
msgid "Tag updated."
|
||||||
msgstr "標籤已更新"
|
msgstr "標籤已更新"
|
||||||
|
|
||||||
|
@ -2698,11 +2698,11 @@ msgstr "總結已發佈到時間軸"
|
||||||
msgid "regarding {item_title}, may contain spoiler or triggering content"
|
msgid "regarding {item_title}, may contain spoiler or triggering content"
|
||||||
msgstr "關於 {item_title},可能包含劇透或敏感內容"
|
msgstr "關於 {item_title},可能包含劇透或敏感內容"
|
||||||
|
|
||||||
#: mastodon/api.py:685
|
#: mastodon/api.py:675
|
||||||
msgid "shared my collection"
|
msgid "shared my collection"
|
||||||
msgstr "分享我的收藏單"
|
msgstr "分享我的收藏單"
|
||||||
|
|
||||||
#: mastodon/api.py:688
|
#: mastodon/api.py:678
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "shared {username}'s collection"
|
msgid "shared {username}'s collection"
|
||||||
msgstr "分享 {username} 的收藏單"
|
msgstr "分享 {username} 的收藏單"
|
||||||
|
@ -2964,31 +2964,31 @@ msgstr "提及"
|
||||||
msgid "follow"
|
msgid "follow"
|
||||||
msgstr "關注"
|
msgstr "關注"
|
||||||
|
|
||||||
#: takahe/models.py:427
|
#: takahe/models.py:430
|
||||||
msgid "Display Name"
|
msgid "Display Name"
|
||||||
msgstr "暱稱"
|
msgstr "暱稱"
|
||||||
|
|
||||||
#: takahe/models.py:429
|
#: takahe/models.py:432
|
||||||
msgid "Bio"
|
msgid "Bio"
|
||||||
msgstr "簡介"
|
msgstr "簡介"
|
||||||
|
|
||||||
#: takahe/models.py:431
|
#: takahe/models.py:434
|
||||||
msgid "Manually approve new followers"
|
msgid "Manually approve new followers"
|
||||||
msgstr "手工審覈關注者"
|
msgstr "手工審覈關注者"
|
||||||
|
|
||||||
#: takahe/models.py:435
|
#: takahe/models.py:438
|
||||||
msgid "Include profile and posts in discovery"
|
msgid "Include profile and posts in discovery"
|
||||||
msgstr "允許個人資料和帖文包含在發現中"
|
msgstr "允許個人資料和帖文包含在發現中"
|
||||||
|
|
||||||
#: takahe/models.py:438
|
#: takahe/models.py:441
|
||||||
msgid "Include posts in search results"
|
msgid "Include posts in search results"
|
||||||
msgstr "允許個人帖文包含在搜索結果中"
|
msgstr "允許個人帖文包含在搜索結果中"
|
||||||
|
|
||||||
#: takahe/models.py:456
|
#: takahe/models.py:459
|
||||||
msgid "Profile picture"
|
msgid "Profile picture"
|
||||||
msgstr "頭像"
|
msgstr "頭像"
|
||||||
|
|
||||||
#: takahe/models.py:463
|
#: takahe/models.py:466
|
||||||
msgid "Header picture"
|
msgid "Header picture"
|
||||||
msgstr "背景圖片"
|
msgstr "背景圖片"
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 4.2.13 on 2024-06-01 05:38
|
# Generated by Django 4.2.13 on 2024-06-04 19:33
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
|
|
||||||
|
@ -102,6 +102,11 @@ class Migration(migrations.Migration):
|
||||||
("public", models.BooleanField(null=True)),
|
("public", models.BooleanField(null=True)),
|
||||||
("state", models.CharField(default="outdated", max_length=100)),
|
("state", models.CharField(default="outdated", max_length=100)),
|
||||||
("state_changed", models.DateTimeField(auto_now_add=True)),
|
("state_changed", models.DateTimeField(auto_now_add=True)),
|
||||||
|
("state_next_attempt", models.DateTimeField(blank=True, null=True)),
|
||||||
|
(
|
||||||
|
"state_locked_until",
|
||||||
|
models.DateTimeField(blank=True, db_index=True, null=True),
|
||||||
|
),
|
||||||
("stats", models.JSONField(blank=True, null=True)),
|
("stats", models.JSONField(blank=True, null=True)),
|
||||||
("stats_updated", models.DateTimeField(blank=True, null=True)),
|
("stats_updated", models.DateTimeField(blank=True, null=True)),
|
||||||
("aliases", models.JSONField(blank=True, null=True)),
|
("aliases", models.JSONField(blank=True, null=True)),
|
||||||
|
@ -162,8 +167,7 @@ class Migration(migrations.Migration):
|
||||||
(
|
(
|
||||||
"indexable",
|
"indexable",
|
||||||
models.BooleanField(
|
models.BooleanField(
|
||||||
default=True,
|
default=True, verbose_name="Include posts in search results"
|
||||||
verbose_name="Include posts in search results",
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
@ -589,6 +593,40 @@ class Migration(migrations.Migration):
|
||||||
blank=True, related_name="identities", to="takahe.user"
|
blank=True, related_name="identities", to="takahe.user"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="HashtagFeature",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("created", models.DateTimeField(auto_now_add=True)),
|
||||||
|
(
|
||||||
|
"hashtag",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="featurers",
|
||||||
|
to="takahe.hashtag",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"identity",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="hashtag_features",
|
||||||
|
to="takahe.identity",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"db_table": "users_hashtagfeature",
|
||||||
|
},
|
||||||
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="FanOut",
|
name="FanOut",
|
||||||
fields=[
|
fields=[
|
||||||
|
|
|
@ -5,7 +5,7 @@ import re
|
||||||
import secrets
|
import secrets
|
||||||
import ssl
|
import ssl
|
||||||
import time
|
import time
|
||||||
from datetime import date
|
from datetime import date, timedelta
|
||||||
from functools import cached_property, partial
|
from functools import cached_property, partial
|
||||||
from typing import TYPE_CHECKING, Literal, Optional
|
from typing import TYPE_CHECKING, Literal, Optional
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
@ -385,7 +385,10 @@ class Identity(models.Model):
|
||||||
Represents both local and remote Fediverse identities (actors)
|
Represents both local and remote Fediverse identities (actors)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
domain_id: str
|
if TYPE_CHECKING:
|
||||||
|
domain_id: str
|
||||||
|
inbound_follows: "models.QuerySet[Follow]"
|
||||||
|
hashtag_features: "models.QuerySet[HashtagFeature]"
|
||||||
|
|
||||||
class Restriction(models.IntegerChoices):
|
class Restriction(models.IntegerChoices):
|
||||||
none = 0
|
none = 0
|
||||||
|
@ -729,6 +732,34 @@ class Identity(models.Model):
|
||||||
self.shared_inbox_uri = f"https://{self.domain.uri_domain}/inbox/"
|
self.shared_inbox_uri = f"https://{self.domain.uri_domain}/inbox/"
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
def get_remote_targets(self):
|
||||||
|
"""
|
||||||
|
Returns an iterable with Identities of followers that have unique
|
||||||
|
shared_inbox among each other to be used as target.
|
||||||
|
"""
|
||||||
|
if not self.local:
|
||||||
|
return []
|
||||||
|
remote_follower_ids = Follow.objects.filter(
|
||||||
|
target=self,
|
||||||
|
target__local=False,
|
||||||
|
state__in=["unrequested", "pending_approval", "accepting", "accepted"],
|
||||||
|
).values_list("source", flat=True)
|
||||||
|
deduped_targets = set()
|
||||||
|
shared_inboxes = set()
|
||||||
|
for target in Identity.objects.filter(pk__in=remote_follower_ids):
|
||||||
|
if not target.shared_inbox_uri:
|
||||||
|
deduped_targets.add(target)
|
||||||
|
elif target.shared_inbox_uri not in shared_inboxes:
|
||||||
|
shared_inboxes.add(target.shared_inbox_uri)
|
||||||
|
deduped_targets.add(target)
|
||||||
|
return deduped_targets
|
||||||
|
|
||||||
|
def fanout(self, type: str, **kwargs):
|
||||||
|
for target in self.get_remote_targets():
|
||||||
|
FanOut.objects.create(
|
||||||
|
identity=target, subject_identity=self, type=type, **kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Follow(models.Model):
|
class Follow(models.Model):
|
||||||
"""
|
"""
|
||||||
|
@ -1569,6 +1600,8 @@ class Hashtag(models.Model):
|
||||||
# state = StateField(HashtagStates)
|
# state = StateField(HashtagStates)
|
||||||
state = models.CharField(max_length=100, default="outdated")
|
state = models.CharField(max_length=100, default="outdated")
|
||||||
state_changed = models.DateTimeField(auto_now_add=True)
|
state_changed = models.DateTimeField(auto_now_add=True)
|
||||||
|
state_next_attempt = models.DateTimeField(blank=True, null=True)
|
||||||
|
state_locked_until = models.DateTimeField(null=True, blank=True, db_index=True)
|
||||||
|
|
||||||
# Metrics for this Hashtag
|
# Metrics for this Hashtag
|
||||||
stats = models.JSONField(null=True, blank=True)
|
stats = models.JSONField(null=True, blank=True)
|
||||||
|
@ -1639,6 +1672,53 @@ class Hashtag(models.Model):
|
||||||
results[date(year, month, day)] = val
|
results[date(year, month, day)] = val
|
||||||
return dict(sorted(results.items(), reverse=True)[:num])
|
return dict(sorted(results.items(), reverse=True)[:num])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def needs_update(self):
|
||||||
|
if self.stats_updated is None:
|
||||||
|
return True
|
||||||
|
return timezone.now() - self.stats_updated > timedelta(hours=1)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def ensure_hashtag(cls, name, update=None):
|
||||||
|
"""
|
||||||
|
Properly strips/trims/lowercases the hashtag name, and makes sure a Hashtag
|
||||||
|
object exists in the database, and returns it.
|
||||||
|
"""
|
||||||
|
name = name.strip().lstrip("#").lower()[: Hashtag.MAXIMUM_LENGTH]
|
||||||
|
hashtag, created = cls.objects.get_or_create(hashtag=name)
|
||||||
|
if created or update or hashtag.needs_update:
|
||||||
|
hashtag.state = "outdated"
|
||||||
|
hashtag.state_changed = timezone.now()
|
||||||
|
hashtag.state_next_attempt = None
|
||||||
|
hashtag.state_locked_until = None
|
||||||
|
hashtag.save(
|
||||||
|
update_fields=[
|
||||||
|
"state",
|
||||||
|
"state_changed",
|
||||||
|
"state_next_attempt",
|
||||||
|
"state_locked_until",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
return hashtag
|
||||||
|
|
||||||
|
|
||||||
|
class HashtagFeature(models.Model):
|
||||||
|
identity = models.ForeignKey(
|
||||||
|
"takahe.Identity",
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="hashtag_features",
|
||||||
|
)
|
||||||
|
hashtag = models.ForeignKey(
|
||||||
|
"takahe.Hashtag",
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="featurers",
|
||||||
|
)
|
||||||
|
|
||||||
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "users_hashtagfeature"
|
||||||
|
|
||||||
|
|
||||||
class PostInteraction(models.Model):
|
class PostInteraction(models.Model):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -990,3 +990,21 @@ class Takahe:
|
||||||
else:
|
else:
|
||||||
qs = qs.filter(visibility__in=[0, 1, 4])
|
qs = qs.filter(visibility__in=[0, 1, 4])
|
||||||
return qs.prefetch_related("attachments", "author")
|
return qs.prefetch_related("attachments", "author")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def pin_hashtag_for_user(identity_pk: int, hashtag: str):
|
||||||
|
tag = Hashtag.ensure_hashtag(hashtag)
|
||||||
|
identity = Identity.objects.get(pk=identity_pk)
|
||||||
|
feature, created = identity.hashtag_features.get_or_create(hashtag=tag)
|
||||||
|
if created:
|
||||||
|
identity.fanout("tag_featured", subject_hashtag=tag)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def unpin_hashtag_for_user(identity_pk: int, hashtag: str):
|
||||||
|
identity = Identity.objects.get(pk=identity_pk)
|
||||||
|
featured = HashtagFeature.objects.filter(
|
||||||
|
identity=identity, hashtag_id=hashtag
|
||||||
|
).first()
|
||||||
|
if featured:
|
||||||
|
identity.fanout("tag_unfeatured", subject_hashtag_id=hashtag)
|
||||||
|
featured.delete()
|
||||||
|
|
Loading…
Add table
Reference in a new issue