mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 19:36:56 -08:00
finish sub-topics fixes #44
This commit is contained in:
parent
bacc0c81be
commit
62292cb6d1
10 changed files with 176 additions and 54 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
from collections import namedtuple
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from random import randint
|
from random import randint
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ from app.constants import SUBSCRIPTION_MEMBER, SUBSCRIPTION_OWNER, POST_TYPE_LIN
|
||||||
SUBSCRIPTION_PENDING, SUBSCRIPTION_MODERATOR
|
SUBSCRIPTION_PENDING, SUBSCRIPTION_MODERATOR
|
||||||
from app.inoculation import inoculation
|
from app.inoculation import inoculation
|
||||||
from app.models import User, Community, CommunityMember, CommunityJoinRequest, CommunityBan, Post, \
|
from app.models import User, Community, CommunityMember, CommunityJoinRequest, CommunityBan, Post, \
|
||||||
File, PostVote, utcnow, Report, Notification, InstanceBlock, ActivityPubLog
|
File, PostVote, utcnow, Report, Notification, InstanceBlock, ActivityPubLog, Topic
|
||||||
from app.community import bp
|
from app.community import bp
|
||||||
from app.utils import get_setting, render_template, allowlist_html, markdown_to_html, validation_required, \
|
from app.utils import get_setting, render_template, allowlist_html, markdown_to_html, validation_required, \
|
||||||
shorten_string, gibberish, community_membership, ap_datetime, \
|
shorten_string, gibberish, community_membership, ap_datetime, \
|
||||||
|
@ -170,11 +171,42 @@ def show_community(community: Community):
|
||||||
per_page = 300
|
per_page = 300
|
||||||
posts = posts.paginate(page=page, per_page=per_page, error_out=False)
|
posts = posts.paginate(page=page, per_page=per_page, error_out=False)
|
||||||
|
|
||||||
|
breadcrumbs = []
|
||||||
|
breadcrumb = namedtuple("Breadcrumb", ['text', 'url'])
|
||||||
|
breadcrumb.text = _('Home')
|
||||||
|
breadcrumb.url = '/'
|
||||||
|
breadcrumbs.append(breadcrumb)
|
||||||
|
|
||||||
if community.topic_id:
|
if community.topic_id:
|
||||||
related_communities = Community.query.filter_by(topic_id=community.topic_id).\
|
related_communities = Community.query.filter_by(topic_id=community.topic_id).\
|
||||||
filter(Community.id != community.id, Community.banned == False).order_by(Community.name)
|
filter(Community.id != community.id, Community.banned == False).order_by(Community.name)
|
||||||
|
topics = []
|
||||||
|
previous_topic = Topic.query.get(community.topic_id)
|
||||||
|
topics.append(previous_topic)
|
||||||
|
while previous_topic.parent_id:
|
||||||
|
topic = Topic.query.get(previous_topic.parent_id)
|
||||||
|
topics.append(topic)
|
||||||
|
previous_topic = topic
|
||||||
|
topics = list(reversed(topics))
|
||||||
|
|
||||||
|
breadcrumb = namedtuple("Breadcrumb", ['text', 'url'])
|
||||||
|
breadcrumb.text = _('Topics')
|
||||||
|
breadcrumb.url = '/topics'
|
||||||
|
breadcrumbs.append(breadcrumb)
|
||||||
|
|
||||||
|
existing_url = '/topic'
|
||||||
|
for topic in topics:
|
||||||
|
breadcrumb = namedtuple("Breadcrumb", ['text', 'url'])
|
||||||
|
breadcrumb.text = topic.name
|
||||||
|
breadcrumb.url = f"{existing_url}/{topic.machine_name}"
|
||||||
|
breadcrumbs.append(breadcrumb)
|
||||||
|
existing_url = breadcrumb.url
|
||||||
else:
|
else:
|
||||||
related_communities = []
|
related_communities = []
|
||||||
|
breadcrumb = namedtuple("Breadcrumb", ['text', 'url'])
|
||||||
|
breadcrumb.text = _('Communities')
|
||||||
|
breadcrumb.url = '/communities'
|
||||||
|
breadcrumbs.append(breadcrumb)
|
||||||
|
|
||||||
description = shorten_string(community.description, 150) if community.description else None
|
description = shorten_string(community.description, 150) if community.description else None
|
||||||
og_image = community.image.source_url if community.image_id else None
|
og_image = community.image.source_url if community.image_id else None
|
||||||
|
@ -184,7 +216,7 @@ def show_community(community: Community):
|
||||||
prev_url = url_for('activitypub.community_profile', actor=community.ap_id if community.ap_id is not None else community.name,
|
prev_url = url_for('activitypub.community_profile', actor=community.ap_id if community.ap_id is not None else community.name,
|
||||||
page=posts.prev_num, sort=sort, layout=post_layout) if posts.has_prev and page != 1 else None
|
page=posts.prev_num, sort=sort, layout=post_layout) if posts.has_prev and page != 1 else None
|
||||||
|
|
||||||
return render_template('community/community.html', community=community, title=community.title,
|
return render_template('community/community.html', community=community, title=community.title, breadcrumbs=breadcrumbs,
|
||||||
is_moderator=is_moderator, is_owner=is_owner, is_admin=is_admin, mods=mod_list, posts=posts, description=description,
|
is_moderator=is_moderator, is_owner=is_owner, is_admin=is_admin, mods=mod_list, posts=posts, description=description,
|
||||||
og_image=og_image, POST_TYPE_IMAGE=POST_TYPE_IMAGE, POST_TYPE_LINK=POST_TYPE_LINK, SUBSCRIPTION_PENDING=SUBSCRIPTION_PENDING,
|
og_image=og_image, POST_TYPE_IMAGE=POST_TYPE_IMAGE, POST_TYPE_LINK=POST_TYPE_LINK, SUBSCRIPTION_PENDING=SUBSCRIPTION_PENDING,
|
||||||
SUBSCRIPTION_MEMBER=SUBSCRIPTION_MEMBER, SUBSCRIPTION_OWNER=SUBSCRIPTION_OWNER, SUBSCRIPTION_MODERATOR=SUBSCRIPTION_MODERATOR,
|
SUBSCRIPTION_MEMBER=SUBSCRIPTION_MEMBER, SUBSCRIPTION_OWNER=SUBSCRIPTION_OWNER, SUBSCRIPTION_MODERATOR=SUBSCRIPTION_MODERATOR,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from collections import namedtuple
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from random import randint
|
from random import randint
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@ from app.community.forms import CreatePostForm
|
||||||
from app.post.util import post_replies, get_comment_branch, post_reply_count
|
from app.post.util import post_replies, get_comment_branch, post_reply_count
|
||||||
from app.constants import SUBSCRIPTION_MEMBER, POST_TYPE_LINK, POST_TYPE_IMAGE
|
from app.constants import SUBSCRIPTION_MEMBER, POST_TYPE_LINK, POST_TYPE_IMAGE
|
||||||
from app.models import Post, PostReply, \
|
from app.models import Post, PostReply, \
|
||||||
PostReplyVote, PostVote, Notification, utcnow, UserBlock, DomainBlock, InstanceBlock, Report, Site, Community
|
PostReplyVote, PostVote, Notification, utcnow, UserBlock, DomainBlock, InstanceBlock, Report, Site, Community, Topic
|
||||||
from app.post import bp
|
from app.post import bp
|
||||||
from app.utils import get_setting, render_template, allowlist_html, markdown_to_html, validation_required, \
|
from app.utils import get_setting, render_template, allowlist_html, markdown_to_html, validation_required, \
|
||||||
shorten_string, markdown_to_text, gibberish, ap_datetime, return_304, \
|
shorten_string, markdown_to_text, gibberish, ap_datetime, return_304, \
|
||||||
|
@ -172,7 +173,45 @@ def show_post(post_id: int):
|
||||||
og_image = post.image.source_url if post.image_id else None
|
og_image = post.image.source_url if post.image_id else None
|
||||||
description = shorten_string(markdown_to_text(post.body), 150) if post.body else None
|
description = shorten_string(markdown_to_text(post.body), 150) if post.body else None
|
||||||
|
|
||||||
|
breadcrumbs = []
|
||||||
|
breadcrumb = namedtuple("Breadcrumb", ['text', 'url'])
|
||||||
|
breadcrumb.text = _('Home')
|
||||||
|
breadcrumb.url = '/'
|
||||||
|
breadcrumbs.append(breadcrumb)
|
||||||
|
|
||||||
|
if community.topic_id:
|
||||||
|
related_communities = Community.query.filter_by(topic_id=community.topic_id).\
|
||||||
|
filter(Community.id != community.id, Community.banned == False).order_by(Community.name)
|
||||||
|
topics = []
|
||||||
|
previous_topic = Topic.query.get(community.topic_id)
|
||||||
|
topics.append(previous_topic)
|
||||||
|
while previous_topic.parent_id:
|
||||||
|
topic = Topic.query.get(previous_topic.parent_id)
|
||||||
|
topics.append(topic)
|
||||||
|
previous_topic = topic
|
||||||
|
topics = list(reversed(topics))
|
||||||
|
|
||||||
|
breadcrumb = namedtuple("Breadcrumb", ['text', 'url'])
|
||||||
|
breadcrumb.text = _('Topics')
|
||||||
|
breadcrumb.url = '/topics'
|
||||||
|
breadcrumbs.append(breadcrumb)
|
||||||
|
|
||||||
|
existing_url = '/topic'
|
||||||
|
for topic in topics:
|
||||||
|
breadcrumb = namedtuple("Breadcrumb", ['text', 'url'])
|
||||||
|
breadcrumb.text = topic.name
|
||||||
|
breadcrumb.url = f"{existing_url}/{topic.machine_name}"
|
||||||
|
breadcrumbs.append(breadcrumb)
|
||||||
|
existing_url = breadcrumb.url
|
||||||
|
else:
|
||||||
|
related_communities = []
|
||||||
|
breadcrumb = namedtuple("Breadcrumb", ['text', 'url'])
|
||||||
|
breadcrumb.text = _('Communities')
|
||||||
|
breadcrumb.url = '/communities'
|
||||||
|
breadcrumbs.append(breadcrumb)
|
||||||
|
|
||||||
response = render_template('post/post.html', title=post.title, post=post, is_moderator=is_moderator, community=post.community,
|
response = render_template('post/post.html', title=post.title, post=post, is_moderator=is_moderator, community=post.community,
|
||||||
|
breadcrumbs=breadcrumbs, related_communities=related_communities,
|
||||||
canonical=post.ap_id, form=form, replies=replies, THREAD_CUTOFF_DEPTH=constants.THREAD_CUTOFF_DEPTH,
|
canonical=post.ap_id, form=form, replies=replies, THREAD_CUTOFF_DEPTH=constants.THREAD_CUTOFF_DEPTH,
|
||||||
description=description, og_image=og_image, POST_TYPE_IMAGE=constants.POST_TYPE_IMAGE,
|
description=description, og_image=og_image, POST_TYPE_IMAGE=constants.POST_TYPE_IMAGE,
|
||||||
POST_TYPE_LINK=constants.POST_TYPE_LINK, POST_TYPE_ARTICLE=constants.POST_TYPE_ARTICLE,
|
POST_TYPE_LINK=constants.POST_TYPE_LINK, POST_TYPE_ARTICLE=constants.POST_TYPE_ARTICLE,
|
||||||
|
|
|
@ -720,6 +720,14 @@ div.navbar {
|
||||||
background-color: var(--bs-card-cap-bg);
|
background-color: var(--bs-card-cap-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#subtopic_nav {
|
||||||
|
position: relative;
|
||||||
|
left: -15px;
|
||||||
|
}
|
||||||
|
#subtopic_nav li a {
|
||||||
|
border: dotted 2px transparent;
|
||||||
|
}
|
||||||
|
|
||||||
/* high contrast */
|
/* high contrast */
|
||||||
@media (prefers-contrast: more) {
|
@media (prefers-contrast: more) {
|
||||||
:root {
|
:root {
|
||||||
|
|
|
@ -338,6 +338,14 @@ div.navbar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#subtopic_nav {
|
||||||
|
position: relative;
|
||||||
|
left: -15px;
|
||||||
|
li a {
|
||||||
|
border: dotted 2px transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* high contrast */
|
/* high contrast */
|
||||||
@media (prefers-contrast: more) {
|
@media (prefers-contrast: more) {
|
||||||
|
|
|
@ -12,11 +12,9 @@
|
||||||
<div class="community_header" style="background-image: url({{ community.header_image() }});">
|
<div class="community_header" style="background-image: url({{ community.header_image() }});">
|
||||||
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
||||||
<ol class="breadcrumb">
|
<ol class="breadcrumb">
|
||||||
<li class="breadcrumb-item"><a href="/">{{ _('Home') }}</a></li>
|
{% for breadcrumb in breadcrumbs %}
|
||||||
{% if community.topic_id %}
|
<li class="breadcrumb-item">{% if breadcrumb.url %}<a href="{{ breadcrumb.url }}">{% endif %}{{ breadcrumb.text }}{% if breadcrumb.url %}</a>{% endif %}</li>
|
||||||
<li class="breadcrumb-item"><a href="/topics">{{ _('Topics') }}</a></li>
|
{% endfor %}
|
||||||
<li class="breadcrumb-item"><a href="/topic/{{ community.topic.machine_name }}" rel="nofollow">{{ community.topic.name }}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
<li class="breadcrumb-item active">{{ (community.title + '@' + community.ap_domain)|shorten }}</li>
|
<li class="breadcrumb-item active">{{ (community.title + '@' + community.ap_domain)|shorten }}</li>
|
||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -31,11 +29,9 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
||||||
<ol class="breadcrumb">
|
<ol class="breadcrumb">
|
||||||
<li class="breadcrumb-item"><a href="/">{{ _('Home') }}</a></li>
|
{% for breadcrumb in breadcrumbs %}
|
||||||
{% if community.topic_id %}
|
<li class="breadcrumb-item">{% if breadcrumb.url %}<a href="{{ breadcrumb.url }}">{% endif %}{{ breadcrumb.text }}{% if breadcrumb.url %}</a>{% endif %}</li>
|
||||||
<li class="breadcrumb-item"><a href="/topics">{{ _('Topics') }}</a></li>
|
{% endfor %}
|
||||||
<li class="breadcrumb-item"><a href="/topic/{{ community.topic.machine_name }}" rel="nofollow">{{ community.topic.name }}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
<li class="breadcrumb-item active">{{ (community.title + '@' + community.ap_domain)|shorten }}</li>
|
<li class="breadcrumb-item active">{{ (community.title + '@' + community.ap_domain)|shorten }}</li>
|
||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -53,11 +49,9 @@
|
||||||
{% else %}
|
{% else %}
|
||||||
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
||||||
<ol class="breadcrumb">
|
<ol class="breadcrumb">
|
||||||
<li class="breadcrumb-item"><a href="/">{{ _('Home') }}</a></li>
|
{% for breadcrumb in breadcrumbs %}
|
||||||
{% if community.topic_id %}
|
<li class="breadcrumb-item">{% if breadcrumb.url %}<a href="{{ breadcrumb.url }}">{% endif %}{{ breadcrumb.text }}{% if breadcrumb.url %}</a>{% endif %}</li>
|
||||||
<li class="breadcrumb-item"><a href="/topics">{{ _('Topics') }}</a></li>
|
{% endfor %}
|
||||||
<li class="breadcrumb-item"><a href="/topic/{{ community.topic.machine_name }}" rel="nofollow">{{ community.topic.name }}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
<li class="breadcrumb-item active">{{ (community.title + '@' + community.ap_domain)|shorten }}</li>
|
<li class="breadcrumb-item active">{{ (community.title + '@' + community.ap_domain)|shorten }}</li>
|
||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
|
@ -3,11 +3,9 @@
|
||||||
<div class="col post_col post_type_image">
|
<div class="col post_col post_type_image">
|
||||||
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
||||||
<ol class="breadcrumb">
|
<ol class="breadcrumb">
|
||||||
<li class="breadcrumb-item"><a href="/">{{ _('Home') }}</a></li>
|
{% for breadcrumb in breadcrumbs %}
|
||||||
{% if community.topic_id %}
|
<li class="breadcrumb-item">{% if breadcrumb.url %}<a href="{{ breadcrumb.url }}">{% endif %}{{ breadcrumb.text }}{% if breadcrumb.url %}</a>{% endif %}</li>
|
||||||
<li class="breadcrumb-item"><a href="/topics">{{ _('Topics') }}</a></li>
|
{% endfor %}
|
||||||
<li class="breadcrumb-item"><a href="/topic/{{ community.topic.machine_name }}" rel="nofollow">{{ community.topic.name }}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
<li class="breadcrumb-item"><a href="/c/{{ post.community.link() }}" title="{{ post.community.ap_domain }}">{{ post.community.title }}@{{ post.community.ap_domain }}</a></li>
|
<li class="breadcrumb-item"><a href="/c/{{ post.community.link() }}" title="{{ post.community.ap_domain }}">{{ post.community.title }}@{{ post.community.ap_domain }}</a></li>
|
||||||
<li class="breadcrumb-item active">{{ post.title|shorten(15) }}</li>
|
<li class="breadcrumb-item active">{{ post.title|shorten(15) }}</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
@ -52,11 +50,9 @@
|
||||||
<div class="col post_col post_type_normal">
|
<div class="col post_col post_type_normal">
|
||||||
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
||||||
<ol class="breadcrumb">
|
<ol class="breadcrumb">
|
||||||
<li class="breadcrumb-item"><a href="/">{{ _('Home') }}</a></li>
|
{% for breadcrumb in breadcrumbs %}
|
||||||
{% if community.topic_id %}
|
<li class="breadcrumb-item">{% if breadcrumb.url %}<a href="{{ breadcrumb.url }}">{% endif %}{{ breadcrumb.text }}{% if breadcrumb.url %}</a>{% endif %}</li>
|
||||||
<li class="breadcrumb-item"><a href="/topics">{{ _('Topics') }}</a></li>
|
{% endfor %}
|
||||||
<li class="breadcrumb-item"><a href="/topic/{{ community.topic.machine_name }}" rel="nofollow">{{ community.topic.name }}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
<li class="breadcrumb-item"><a href="/c/{{ post.community.link() }}">{{ post.community.title }}@{{ post.community.ap_domain }}</a></li>
|
<li class="breadcrumb-item"><a href="/c/{{ post.community.link() }}">{{ post.community.title }}@{{ post.community.ap_domain }}</a></li>
|
||||||
<li class="breadcrumb-item active">{{ post.title|shorten(15) }}</li>
|
<li class="breadcrumb-item active">{{ post.title|shorten(15) }}</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
|
@ -77,7 +77,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-2"><a href="{{ url_for('post.post_options', post_id=post.id) }}" rel="nofollow" class="post_options" aria-label="{{ _('Options') }}"><span class="fe fe-options" title="Options"> </span></a></div>
|
<div class="col-6 text-right"><a href="{{ url_for('post.post_options', post_id=post.id) }}" rel="nofollow" class="post_options" aria-label="{{ _('Options') }}"><span class="fe fe-options" title="Options"> </span></a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
{% if post.community.ap_id and '@beehaw.org' in post.community.ap_id %}
|
{% if post.community.ap_id and '@beehaw.org' in post.community.ap_id %}
|
||||||
<p>{{ _('This post is hosted on beehaw.org which has <a href="https://docs.beehaw.org/docs/core-principles/what-is-beehaw/" target="_blank" rel="nofollow">higher standards of behaviour than most places. Be nice</a>.') }}</p>
|
<p>{{ _('This post is hosted on beehaw.org which has <a href="https://docs.beehaw.org/docs/core-principles/what-is-beehaw/" target="_blank" rel="nofollow">higher standards of behaviour than most places. Be nice</a>.') }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if post.community.ap_id and '@lemmy.ml' in post.community.ap_id %}
|
||||||
|
<p>{{ _('This post is hosted on lemmy.ml which will ban you for saying anything negative about China, Russia or Putin. Tread carefully.') }}</p>
|
||||||
|
{% endif %}
|
||||||
{{ render_form(form) }}
|
{{ render_form(form) }}
|
||||||
{% if not low_bandwidth %}
|
{% if not low_bandwidth %}
|
||||||
{% if markdown_editor %}
|
{% if markdown_editor %}
|
||||||
|
@ -196,6 +199,25 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% if related_communities %}
|
||||||
|
<div class="card mt-3">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2>{{ _('Related communities') }}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<ul class="list-group list-group-flush">
|
||||||
|
{% for community in related_communities %}
|
||||||
|
<li class="list-group-item">
|
||||||
|
<a href="/c/{{ community.link() }}" aria-label="{{ _('Go to community') }}"><img src="{{ community.icon_image() }}" class="community_icon rounded-circle" loading="lazy" alt="" />
|
||||||
|
{{ community.display_name() }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<p class="mt-4"><a class="btn btn-primary" href="/communities">{{ _('Explore communities') }}</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% if is_moderator %}
|
{% if is_moderator %}
|
||||||
<div class="card mt-3">
|
<div class="card mt-3">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
|
|
|
@ -12,16 +12,18 @@
|
||||||
<ol class="breadcrumb">
|
<ol class="breadcrumb">
|
||||||
<li class="breadcrumb-item"><a href="/">{{ _('Home') }}</a></li>
|
<li class="breadcrumb-item"><a href="/">{{ _('Home') }}</a></li>
|
||||||
<li class="breadcrumb-item"><a href="/topics">{{ _('Topics') }}</a></li>
|
<li class="breadcrumb-item"><a href="/topics">{{ _('Topics') }}</a></li>
|
||||||
<li class="breadcrumb-item active">{{ topic.name|shorten }}</li>
|
{% for breadcrumb in breadcrumbs %}
|
||||||
|
<li class="breadcrumb-item">{% if breadcrumb.url %}<a href="{{ breadcrumb.url }}">{% endif %}{{ breadcrumb.text }}{% if breadcrumb.url %}</a>{% endif %}</li>
|
||||||
|
{% endfor %}
|
||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
<h1 class="mt-2">{{ topic.name }}
|
<h1 class="mt-2">{{ topic.name }}
|
||||||
</h1>
|
</h1>
|
||||||
{% if sub_topics %}
|
{% if sub_topics %}
|
||||||
<h3 class="mb-0" id="sub-topics">{{ _('Sub-topics') }}</h3>
|
<h5 class="mb-0" id="sub-topics">{{ _('Sub-topics') }}</h5>
|
||||||
<ul class="nav" role="listbox" aria-labelledby="sub-topics">
|
<ul id="subtopic_nav" class="nav" role="listbox" aria-labelledby="sub-topics">
|
||||||
{% for topic in sub_topics %}
|
{% for sub_topic in sub_topics %}
|
||||||
<li class="nav-item" role="option"><a class="nav-link" href="/topic/{{ topic.machine_name }}">{{ topic.name }}</a></li>
|
<li class="nav-item" role="option"><a class="nav-link" href="/topic/{{ topic_path }}/{{ sub_topic.machine_name }}">{{ sub_topic.name }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from collections import namedtuple
|
||||||
from datetime import timedelta, timezone
|
from datetime import timedelta, timezone
|
||||||
from random import randint
|
from random import randint
|
||||||
|
|
||||||
|
@ -18,8 +19,8 @@ from app.utils import render_template, user_filters_posts, moderating_communitie
|
||||||
community_membership, blocked_domains, validation_required, mimetype_from_url
|
community_membership, blocked_domains, validation_required, mimetype_from_url
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/topic/<topic_name>', methods=['GET'])
|
@bp.route('/topic/<path:topic_path>', methods=['GET'])
|
||||||
def show_topic(topic_name):
|
def show_topic(topic_path):
|
||||||
|
|
||||||
page = request.args.get('page', 1, type=int)
|
page = request.args.get('page', 1, type=int)
|
||||||
sort = request.args.get('sort', '' if current_user.is_anonymous else current_user.default_sort)
|
sort = request.args.get('sort', '' if current_user.is_anonymous else current_user.default_sort)
|
||||||
|
@ -27,11 +28,26 @@ def show_topic(topic_name):
|
||||||
post_layout = request.args.get('layout', 'list' if not low_bandwidth else None)
|
post_layout = request.args.get('layout', 'list' if not low_bandwidth else None)
|
||||||
|
|
||||||
# translate topic_name from /topic/fediverse to topic_id
|
# translate topic_name from /topic/fediverse to topic_id
|
||||||
topic = Topic.query.filter(Topic.machine_name == topic_name.strip().lower()).first()
|
topic_url_parts = topic_path.split('/')
|
||||||
|
last_topic_machine_name = topic_url_parts[-1]
|
||||||
|
breadcrumbs = []
|
||||||
|
existing_url = '/topic'
|
||||||
|
topic = None
|
||||||
|
for url_part in topic_url_parts:
|
||||||
|
topic = Topic.query.filter(Topic.machine_name == url_part.strip().lower()).first()
|
||||||
|
if topic:
|
||||||
|
breadcrumb = namedtuple("Breadcrumb", ['text', 'url'])
|
||||||
|
breadcrumb.text = topic.name
|
||||||
|
breadcrumb.url = f"{existing_url}/{topic.machine_name}" if topic.machine_name != last_topic_machine_name else ''
|
||||||
|
breadcrumbs.append(breadcrumb)
|
||||||
|
existing_url = breadcrumb.url
|
||||||
|
else:
|
||||||
|
abort(404)
|
||||||
|
current_topic = topic
|
||||||
|
|
||||||
if topic:
|
if current_topic:
|
||||||
# get posts from communities in that topic
|
# get posts from communities in that topic
|
||||||
posts = Post.query.join(Community, Post.community_id == Community.id).filter(Community.topic_id == topic.id, Community.banned == False)
|
posts = Post.query.join(Community, Post.community_id == Community.id).filter(Community.topic_id == current_topic.id, Community.banned == False)
|
||||||
|
|
||||||
# filter out nsfw and nsfl if desired
|
# filter out nsfw and nsfl if desired
|
||||||
if current_user.is_anonymous:
|
if current_user.is_anonymous:
|
||||||
|
@ -68,23 +84,23 @@ def show_topic(topic_name):
|
||||||
per_page = 300
|
per_page = 300
|
||||||
posts = posts.paginate(page=page, per_page=per_page, error_out=False)
|
posts = posts.paginate(page=page, per_page=per_page, error_out=False)
|
||||||
|
|
||||||
topic_communities = Community.query.filter(Community.topic_id == topic.id).order_by(Community.name)
|
topic_communities = Community.query.filter(Community.topic_id == current_topic.id).order_by(Community.name)
|
||||||
|
|
||||||
next_url = url_for('topic.show_topic',
|
next_url = url_for('topic.show_topic',
|
||||||
topic_name=topic_name,
|
topic_path=topic_path,
|
||||||
page=posts.next_num, sort=sort, layout=post_layout) if posts.has_next else None
|
page=posts.next_num, sort=sort, layout=post_layout) if posts.has_next else None
|
||||||
prev_url = url_for('topic.show_topic',
|
prev_url = url_for('topic.show_topic',
|
||||||
topic_name=topic_name,
|
topic_path=topic_path,
|
||||||
page=posts.prev_num, sort=sort, layout=post_layout) if posts.has_prev and page != 1 else None
|
page=posts.prev_num, sort=sort, layout=post_layout) if posts.has_prev and page != 1 else None
|
||||||
|
|
||||||
sub_topics = Topic.query.filter_by(parent_id=topic.id).order_by(Topic.name).all()
|
sub_topics = Topic.query.filter_by(parent_id=current_topic.id).order_by(Topic.name).all()
|
||||||
|
|
||||||
return render_template('topic/show_topic.html', title=_(topic.name), posts=posts, topic=topic, sort=sort,
|
return render_template('topic/show_topic.html', title=_(current_topic.name), posts=posts, topic=current_topic, sort=sort,
|
||||||
page=page, post_layout=post_layout, next_url=next_url, prev_url=prev_url,
|
page=page, post_layout=post_layout, next_url=next_url, prev_url=prev_url,
|
||||||
topic_communities=topic_communities, content_filters=content_filters,
|
topic_communities=topic_communities, content_filters=content_filters,
|
||||||
sub_topics=sub_topics,
|
sub_topics=sub_topics, topic_path=topic_path, breadcrumbs=breadcrumbs,
|
||||||
rss_feed=f"https://{current_app.config['SERVER_NAME']}/topic/{topic_name}.rss",
|
rss_feed=f"https://{current_app.config['SERVER_NAME']}/topic/{topic_path}.rss",
|
||||||
rss_feed_name=f"{topic.name} on {g.site.name}",
|
rss_feed_name=f"{current_topic.name} on {g.site.name}",
|
||||||
show_post_community=True, moderating_communities=moderating_communities(current_user.get_id()),
|
show_post_community=True, moderating_communities=moderating_communities(current_user.get_id()),
|
||||||
joined_communities=joined_communities(current_user.get_id()),
|
joined_communities=joined_communities(current_user.get_id()),
|
||||||
inoculation=inoculation[randint(0, len(inoculation) - 1)],
|
inoculation=inoculation[randint(0, len(inoculation) - 1)],
|
||||||
|
@ -93,10 +109,12 @@ def show_topic(topic_name):
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/topic/<topic_name>.rss', methods=['GET'])
|
@bp.route('/topic/<path:topic_path>.rss', methods=['GET'])
|
||||||
@cache.cached(timeout=600)
|
@cache.cached(timeout=600)
|
||||||
def show_topic_rss(topic_name):
|
def show_topic_rss(topic_path):
|
||||||
topic = Topic.query.filter(Topic.machine_name == topic_name.strip().lower()).first()
|
topic_url_parts = topic_path.split('/')
|
||||||
|
last_topic_machine_name = topic_url_parts[-1]
|
||||||
|
topic = Topic.query.filter(Topic.machine_name == last_topic_machine_name.strip().lower()).first()
|
||||||
|
|
||||||
if topic:
|
if topic:
|
||||||
posts = Post.query.join(Community, Post.community_id == Community.id).filter(Community.topic_id == topic.id,
|
posts = Post.query.join(Community, Post.community_id == Community.id).filter(Community.topic_id == topic.id,
|
||||||
|
@ -105,12 +123,12 @@ def show_topic_rss(topic_name):
|
||||||
posts = posts.order_by(desc(Post.created_at)).limit(100).all()
|
posts = posts.order_by(desc(Post.created_at)).limit(100).all()
|
||||||
|
|
||||||
fg = FeedGenerator()
|
fg = FeedGenerator()
|
||||||
fg.id(f"https://{current_app.config['SERVER_NAME']}/topic/{topic_name}")
|
fg.id(f"https://{current_app.config['SERVER_NAME']}/topic/{last_topic_machine_name}")
|
||||||
fg.title(f'{topic.name} on {g.site.name}')
|
fg.title(f'{topic.name} on {g.site.name}')
|
||||||
fg.link(href=f"https://{current_app.config['SERVER_NAME']}/topic/{topic_name}", rel='alternate')
|
fg.link(href=f"https://{current_app.config['SERVER_NAME']}/topic/{last_topic_machine_name}", rel='alternate')
|
||||||
fg.logo(f"https://{current_app.config['SERVER_NAME']}/static/images/apple-touch-icon.png")
|
fg.logo(f"https://{current_app.config['SERVER_NAME']}/static/images/apple-touch-icon.png")
|
||||||
fg.subtitle(' ')
|
fg.subtitle(' ')
|
||||||
fg.link(href=f"https://{current_app.config['SERVER_NAME']}/topic/{topic_name}.rss", rel='self')
|
fg.link(href=f"https://{current_app.config['SERVER_NAME']}/topic/{last_topic_machine_name}.rss", rel='self')
|
||||||
fg.language('en')
|
fg.language('en')
|
||||||
|
|
||||||
for post in posts:
|
for post in posts:
|
||||||
|
@ -174,10 +192,13 @@ def topic_create_post(topic_name):
|
||||||
|
|
||||||
|
|
||||||
def topics_for_form():
|
def topics_for_form():
|
||||||
topics = Topic.query.order_by(Topic.name).all()
|
topics = Topic.query.filter_by(parent_id=None).order_by(Topic.name).all()
|
||||||
result = []
|
result = []
|
||||||
for topic in topics:
|
for topic in topics:
|
||||||
result.append((topic.id, topic.name))
|
result.append((topic.id, topic.name))
|
||||||
|
sub_topics = Topic.query.filter_by(parent_id=topic.id).order_by(Topic.name).all()
|
||||||
|
for sub_topic in sub_topics:
|
||||||
|
result.append((sub_topic.id, ' --- ' + sub_topic.name))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue