mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 11:26:56 -08:00
organise communities under topics
This commit is contained in:
parent
04a4abe9d5
commit
241fe8ec38
18 changed files with 383 additions and 29 deletions
|
@ -74,6 +74,9 @@ def create_app(config_class=Config):
|
|||
from app.domain import bp as domain_bp
|
||||
app.register_blueprint(domain_bp)
|
||||
|
||||
from app.topic import bp as topic_bp
|
||||
app.register_blueprint(topic_bp)
|
||||
|
||||
def get_resource_as_string(name, charset='utf-8'):
|
||||
with app.open_resource(name) as f:
|
||||
return f.read().decode(charset)
|
||||
|
|
|
@ -57,7 +57,10 @@ def login():
|
|||
db.session.commit()
|
||||
next_page = request.args.get('next')
|
||||
if not next_page or url_parse(next_page).netloc != '':
|
||||
next_page = url_for('main.index')
|
||||
if len(current_user.communities()) == 0:
|
||||
next_page = url_for('topic.choose_topics')
|
||||
else:
|
||||
next_page = url_for('main.index')
|
||||
response = make_response(redirect(next_page))
|
||||
if form.low_bandwidth_mode.data:
|
||||
response.set_cookie('low_bandwidth', '1', expires=datetime(year=2099, month=12, day=30))
|
||||
|
@ -108,9 +111,9 @@ def register():
|
|||
if current_app.config['MODE'] == 'development':
|
||||
current_app.logger.info('Verify account:' + url_for('auth.verify_email', token=user.verification_token, _external=True))
|
||||
|
||||
flash(_('Great, you are now a registered user! Choose some communities to join. Use the topic filter to narrow things down.'))
|
||||
flash(_('Great, you are now a registered user!'))
|
||||
|
||||
resp = make_response(redirect(url_for('main.list_communities')))
|
||||
resp = make_response(redirect(url_for('topic.choose_topics')))
|
||||
if user_ip_banned():
|
||||
resp.set_cookie('sesion', '17489047567495', expires=datetime(year=2099, month=12, day=30))
|
||||
return resp
|
||||
|
@ -176,7 +179,10 @@ def verify_email(token):
|
|||
flash(_('Thank you for verifying your email address.'))
|
||||
else:
|
||||
flash(_('Email address validation failed.'), 'error')
|
||||
return redirect(url_for('main.index'))
|
||||
if len(user.communities()) == 0:
|
||||
return redirect(url_for('topic.choose_topics'))
|
||||
else:
|
||||
return redirect(url_for('main.index'))
|
||||
|
||||
|
||||
@bp.route('/validation_required')
|
||||
|
|
|
@ -315,7 +315,7 @@ def unsubscribe(actor):
|
|||
activity.result = 'success'
|
||||
db.session.commit()
|
||||
if not success:
|
||||
flash('There was a problem while trying to join', 'error')
|
||||
flash('There was a problem while trying to unsubscribe', 'error')
|
||||
|
||||
if proceed:
|
||||
db.session.query(CommunityMember).filter_by(user_id=current_user.id, community_id=community.id).delete()
|
||||
|
|
|
@ -121,6 +121,7 @@ class File(db.Model):
|
|||
|
||||
class Topic(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
machine_name = db.Column(db.String(50), index=True)
|
||||
name = db.Column(db.String(50))
|
||||
num_communities = db.Column(db.Integer, default=0)
|
||||
communities = db.relationship('Community', lazy='dynamic', backref='topic', cascade="all, delete-orphan")
|
||||
|
@ -540,7 +541,7 @@ class User(UserMixin, db.Model):
|
|||
|
||||
def communities(self) -> List[Community]:
|
||||
return Community.query.filter(Community.banned == False).\
|
||||
join(CommunityMember).filter(CommunityMember.is_banned == False).all()
|
||||
join(CommunityMember).filter(CommunityMember.is_banned == False, CommunityMember.user_id == self.id).all()
|
||||
|
||||
def profile_id(self):
|
||||
return self.ap_profile_id if self.ap_profile_id else f"https://{current_app.config['SERVER_NAME']}/u/{self.user_name}"
|
||||
|
|
|
@ -478,6 +478,16 @@ fieldset legend {
|
|||
content: ">";
|
||||
}
|
||||
}
|
||||
.communities_table tbody tr th {
|
||||
padding: 0;
|
||||
}
|
||||
.communities_table tbody tr th a {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.community_header {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
|
@ -528,6 +538,25 @@ fieldset legend {
|
|||
height: auto;
|
||||
}
|
||||
|
||||
#choose_topics_card label.form-control-label {
|
||||
display: none;
|
||||
}
|
||||
#choose_topics_card .form-group {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
#choose_topics_card ul.form-control {
|
||||
border: none;
|
||||
list-style-type: none;
|
||||
padding-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
#choose_topics_card ul.form-control li {
|
||||
vertical-align: center;
|
||||
}
|
||||
#choose_topics_card ul.form-control li label {
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.form-check .form-check-input {
|
||||
position: relative;
|
||||
top: 4px;
|
||||
|
|
|
@ -82,6 +82,18 @@ nav, etc which are used site-wide */
|
|||
}
|
||||
}
|
||||
|
||||
.communities_table {
|
||||
tbody tr th {
|
||||
padding: 0;
|
||||
a {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.community_header {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
|
@ -133,6 +145,27 @@ nav, etc which are used site-wide */
|
|||
}
|
||||
}
|
||||
|
||||
#choose_topics_card {
|
||||
label.form-control-label {
|
||||
display: none;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
ul.form-control {
|
||||
border: none;
|
||||
list-style-type: none;
|
||||
padding-top: 0;
|
||||
margin-bottom: 0;
|
||||
li {
|
||||
vertical-align: center;
|
||||
label {
|
||||
height: 44px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-check .form-check-input {
|
||||
position: relative;
|
||||
top: 4px;
|
||||
|
|
|
@ -122,10 +122,10 @@
|
|||
<li><a class="dropdown-item{% if active_child == 'all_posts' %} active{% endif %}" href="/all"><span class="fe fe-all"></span>{{ _('All posts') }}</a></li>
|
||||
</ul>
|
||||
<li class="nav-item dropdown{% if active_parent == 'communities' %} active{% endif %}">
|
||||
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="/communities" aria-haspopup="true" aria-expanded="false">{{ _('Communities') }}</a>
|
||||
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="/topics" aria-haspopup="true" aria-expanded="false">{{ _('Topics') }}</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item{% if active_child == 'list_communities' %} active{% endif %}" href="/communities">{{ _('Browse all') }}</a></li>
|
||||
<li><a class="dropdown-item{% if active_child == 'list_topics' %} active{% endif %}" href="/topics">{{ _('By topic') }}</a></li>
|
||||
<li><a class="dropdown-item{% if active_child == 'list_communities' %} active{% endif %}" href="/topics">{{ _('Browse by topic') }}</a></li>
|
||||
<li><a class="dropdown-item{% if active_child == 'list_topics' %} active{% endif %}" href="/communities">{{ _('All communities') }}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="/auth/login">{{ _('Log in') }}</a></li>
|
||||
|
@ -140,10 +140,10 @@
|
|||
<li><a class="dropdown-item{% if active_child == 'all_posts' %} active{% endif %}" href="/all"><span class="fe fe-all"></span>{{ _('All posts') }}</a></li>
|
||||
</ul>
|
||||
<li class="nav-item dropdown{% if active_parent == 'communities' %} active{% endif %}">
|
||||
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="/communities" aria-haspopup="true" aria-expanded="false">{{ _('Communities') }}</a>
|
||||
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="/topics" aria-haspopup="true" aria-expanded="false">{{ _('Topics') }}</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item{% if active_child == 'list_communities' %} active{% endif %}" href="/communities">{{ _('Browse all') }}</a></li>
|
||||
<li><a class="dropdown-item{% if active_child == 'list_topics' %} active{% endif %}" href="/topics">{{ _('By topic') }}</a></li>
|
||||
<li><a class="dropdown-item{% if active_child == 'list_communities' %} active{% endif %}" href="/topics">{{ _('Browse by topic') }}</a></li>
|
||||
<li><a class="dropdown-item{% if active_child == 'list_topics' %} active{% endif %}" href="/communities">{{ _('All communities') }}</a></li>
|
||||
{% if moderating_communities %}
|
||||
<li><h6 class="dropdown-header">{{ _('Moderating') }}</h6></li>
|
||||
{% for community in moderating_communities %}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<div class="mobile_create_post d-md-none mt-1">
|
||||
<a class="btn btn-primary" href="/community/{{ community.link() }}/submit">{{ _('Create post') }}</a>
|
||||
</div>
|
||||
{% if community %}
|
||||
<div class="mobile_create_post d-md-none mt-1">
|
||||
<a class="btn btn-primary" href="/community/{{ community.link() }}/submit">{{ _('Create post') }}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="btn-group mt-1 mb-2">
|
||||
<a href="?sort=hot&layout={{ post_layout }}" class="btn {{ 'btn-primary' if sort == '' or sort == 'hot' else 'btn-outline-secondary' }}" rel="nofollow">
|
||||
{{ _('Hot') }}
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/">{{ _('Home') }}</a></li>
|
||||
<li class="breadcrumb-item"><a href="/communities">{{ _('Communities') }}</a></li>
|
||||
{% if community.topic_id %}
|
||||
<li class="breadcrumb-item"><a href="/communities?topic_id={{ community.topic.id }}" rel="nofollow">{{ community.topic.name }}</a></li>
|
||||
<li class="breadcrumb-item"><a href="/topics">{{ _('Topics') }}</a></li>
|
||||
<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|shorten }}</li>
|
||||
</ol>
|
||||
|
@ -28,9 +28,9 @@
|
|||
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/">{{ _('Home') }}</a></li>
|
||||
<li class="breadcrumb-item"><a href="/communities">{{ _('Communities') }}</a></li>
|
||||
{% if community.topic_id %}
|
||||
<li class="breadcrumb-item"><a href="/communities?topic_id={{ community.topic.id }}" rel="nofollow">{{ community.topic.name }}</a></li>
|
||||
<li class="breadcrumb-item"><a href="/topics">{{ _('Topics') }}</a></li>
|
||||
<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|shorten }}</li>
|
||||
</ol>
|
||||
|
@ -50,9 +50,9 @@
|
|||
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/">{{ _('Home') }}</a></li>
|
||||
<li class="breadcrumb-item"><a href="/communities">{{ _('Communities') }}</a></li>
|
||||
{% if community.topic_id %}
|
||||
<li class="breadcrumb-item"><a href="/communities?topic_id={{ community.topic.id }}" rel="nofollow">{{ community.topic.name }}</a></li>
|
||||
<li class="breadcrumb-item"><a href="/topics">{{ _('Topics') }}</a></li>
|
||||
<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|shorten }}</li>
|
||||
</ol>
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
<table class="communities_table table table-striped table-hover w-100">
|
||||
<tbody>
|
||||
{% for topic in topics %}
|
||||
<tr class="">
|
||||
<td><a href="/communities?topic_id={{ topic.id }}">{{ topic.name }}</a></td>
|
||||
<tr>
|
||||
<th class="pl-2"><a href="/topic/{{ topic.machine_name }}">{{ topic.name }}</a></th>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
@ -18,4 +18,5 @@
|
|||
{% else %}
|
||||
<p>{{ _('There are no communities yet.') }}</p>
|
||||
{% endif %}
|
||||
<p><a href="/communities" class="btn btn-primary">{{ _('Explore communities') }}</a></p>
|
||||
{% endblock %}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/">{{ _('Home') }}</a></li>
|
||||
<li class="breadcrumb-item"><a href="/communities">{{ _('Communities') }}</a></li>
|
||||
{% if post.community.topic_id %}
|
||||
<li class="breadcrumb-item"><a href="/communities?topic_id={{ post.community.topic.id }}" rel="nofollow">{{ post.community.topic.name }}</a></li>
|
||||
{% if community.topic_id %}
|
||||
<li class="breadcrumb-item"><a href="/topics">{{ _('Topics') }}</a></li>
|
||||
<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 }}</a></li>
|
||||
<li class="breadcrumb-item active">{{ post.title|shorten(15) }}</li>
|
||||
|
@ -51,9 +51,9 @@
|
|||
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/">{{ _('Home') }}</a></li>
|
||||
<li class="breadcrumb-item"><a href="/communities">{{ _('Communities') }}</a></li>
|
||||
{% if post.community.topic_id %}
|
||||
<li class="breadcrumb-item"><a href="/communities?topic_id={{ post.community.topic.id }}" rel="nofollow">{{ post.community.topic.name }}</a></li>
|
||||
{% if community.topic_id %}
|
||||
<li class="breadcrumb-item"><a href="/topics">{{ _('Topics') }}</a></li>
|
||||
<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 }}</a></li>
|
||||
<li class="breadcrumb-item active">{{ post.title|shorten(15) }}</li>
|
||||
|
|
16
app/templates/topic/choose_topics.html
Normal file
16
app/templates/topic/choose_topics.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
{% extends 'base.html' %}
|
||||
{% from 'bootstrap/form.html' import render_form %}
|
||||
|
||||
{% block app_content %}
|
||||
<div class="row">
|
||||
<div class="col col-login mx-auto">
|
||||
<div class="card mt-5">
|
||||
<div class="card-body p-6" id="choose_topics_card">
|
||||
<div class="card-title text-center">{{ _('Please choose at least 3 topics that interest you.') }}</div>
|
||||
{{ render_form(form) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
77
app/templates/topic/show_topic.html
Normal file
77
app/templates/topic/show_topic.html
Normal file
|
@ -0,0 +1,77 @@
|
|||
{% extends "base.html" %}
|
||||
{% from 'bootstrap/form.html' import render_form %}
|
||||
|
||||
{% block app_content %}
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-8 position-relative main_pane">
|
||||
<nav aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/">{{ _('Home') }}</a></li>
|
||||
<li class="breadcrumb-item"><a href="/topics">{{ _('Topics') }}</a></li>
|
||||
<li class="breadcrumb-item active">{{ topic.name|shorten }}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
<h1 class="mt-2">{{ topic.name }}
|
||||
</h1>
|
||||
|
||||
{% include "community/_community_nav.html" %}
|
||||
{% if post_layout == 'masonry' or post_layout == 'masonry_wide' %}
|
||||
<div class="post_list_{{ post_layout }}">
|
||||
{% for post in posts %}
|
||||
{% include 'post/_post_teaser_masonry.html' %}
|
||||
{% else %}
|
||||
<p>{{ _('No posts in this topic yet.') }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="post_list">
|
||||
{% for post in posts %}
|
||||
{% include 'post/_post_teaser.html' %}
|
||||
{% else %}
|
||||
<p>{{ _('No posts in this topic yet.') }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<nav aria-label="Pagination" class="mt-4" role="navigation">
|
||||
{% if prev_url %}
|
||||
<a href="{{ prev_url }}" class="btn btn-primary" rel='nofollow'>
|
||||
<span aria-hidden="true">←</span> {{ _('Previous page') }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if next_url %}
|
||||
<a href="{{ next_url }}" class="btn btn-primary" rel='nofollow'>
|
||||
{{ _('Next page') }} <span aria-hidden="true">→</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-4 side_pane" role="complementary">
|
||||
{% if topic_communities %}
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">
|
||||
<h2>{{ _('Topic communities') }}</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-group list-group-flush">
|
||||
{% for community in topic_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 %}
|
||||
{% include "_inoculation_links.html" %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
5
app/topic/__init__.py
Normal file
5
app/topic/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from flask import Blueprint
|
||||
|
||||
bp = Blueprint('topic', __name__)
|
||||
|
||||
from app.topic import routes
|
14
app/topic/forms.py
Normal file
14
app/topic/forms.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
from flask import request
|
||||
from flask_login import current_user
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, SubmitField, TextAreaField, BooleanField, HiddenField, SelectField, FileField
|
||||
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo, Length, Optional
|
||||
from flask_babel import _, lazy_gettext as _l
|
||||
from app.utils import MultiCheckboxField
|
||||
|
||||
from app import db
|
||||
|
||||
|
||||
class ChooseTopicsForm(FlaskForm):
|
||||
chosen_topics = MultiCheckboxField(_l('Choose some topics you are interested in'), coerce=int)
|
||||
submit = SubmitField(_l('Choose'))
|
131
app/topic/routes.py
Normal file
131
app/topic/routes.py
Normal file
|
@ -0,0 +1,131 @@
|
|||
from datetime import timedelta
|
||||
from random import randint
|
||||
|
||||
from flask import request, flash, json, url_for, current_app, redirect, abort
|
||||
from flask_login import login_required, current_user
|
||||
from flask_babel import _
|
||||
from sqlalchemy import text, desc
|
||||
|
||||
from app.activitypub.signature import post_request
|
||||
from app.constants import SUBSCRIPTION_NONMEMBER
|
||||
from app.inoculation import inoculation
|
||||
from app.models import Topic, Community, Post, utcnow, CommunityMember, CommunityJoinRequest
|
||||
from app.topic import bp
|
||||
from app import db, celery, cache
|
||||
from app.topic.forms import ChooseTopicsForm
|
||||
from app.utils import render_template, user_filters_posts, moderating_communities, joined_communities, \
|
||||
community_membership
|
||||
|
||||
|
||||
@bp.route('/topic/<topic_name>', methods=['GET'])
|
||||
def show_topic(topic_name):
|
||||
|
||||
page = request.args.get('page', 1, type=int)
|
||||
sort = request.args.get('sort', '' if current_user.is_anonymous else current_user.default_sort)
|
||||
low_bandwidth = request.cookies.get('low_bandwidth', '0') == '1'
|
||||
post_layout = request.args.get('layout', 'list' if not low_bandwidth else None)
|
||||
|
||||
# translate topic_name from /topic/fediverse to topic_id
|
||||
topic = Topic.query.filter(Topic.machine_name == topic_name.strip().lower()).first()
|
||||
|
||||
if 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)
|
||||
if sort == '' or sort == 'hot':
|
||||
posts = posts.order_by(desc(Post.ranking))
|
||||
elif sort == 'top':
|
||||
posts = posts.filter(Post.posted_at > utcnow() - timedelta(days=7)).order_by(desc(Post.score))
|
||||
elif sort == 'new':
|
||||
posts = posts.order_by(desc(Post.posted_at))
|
||||
elif sort == 'active':
|
||||
posts = posts.order_by(desc(Post.last_active))
|
||||
if current_user.is_anonymous or current_user.ignore_bots:
|
||||
posts = posts.filter(Post.from_bot == False)
|
||||
content_filters = {}
|
||||
else:
|
||||
content_filters = user_filters_posts(current_user.id)
|
||||
per_page = 100
|
||||
if post_layout == 'masonry':
|
||||
per_page = 200
|
||||
elif post_layout == 'masonry_wide':
|
||||
per_page = 300
|
||||
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)
|
||||
|
||||
next_url = url_for('topic.show_topic',
|
||||
topic_name=topic_name,
|
||||
page=posts.next_num, sort=sort, layout=post_layout) if posts.has_next else None
|
||||
prev_url = url_for('topic.show_topic',
|
||||
topic_name=topic_name,
|
||||
page=posts.prev_num, sort=sort, layout=post_layout) if posts.has_prev and page != 1 else None
|
||||
|
||||
return render_template('topic/show_topic.html', title=_(topic.name), posts=posts, topic=topic, sort=sort,
|
||||
page=page, post_layout=post_layout, next_url=next_url, prev_url=prev_url,
|
||||
topic_communities=topic_communities, content_filters=content_filters,
|
||||
show_post_community=True, moderating_communities=moderating_communities(current_user.get_id()),
|
||||
joined_communities=joined_communities(current_user.get_id()),
|
||||
inoculation=inoculation[randint(0, len(inoculation) - 1)])
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
||||
@bp.route('/choose_topics', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def choose_topics():
|
||||
form = ChooseTopicsForm()
|
||||
form.chosen_topics.choices = topics_for_form()
|
||||
if form.validate_on_submit():
|
||||
if form.chosen_topics.data:
|
||||
for topic_id in form.chosen_topics.data:
|
||||
join_topic(topic_id)
|
||||
flash(_('You have joined some communities relating to those interests. Find them on the Topics menu or browse the home page.'))
|
||||
cache.delete_memoized(joined_communities, current_user.id)
|
||||
return redirect(url_for('main.index'))
|
||||
else:
|
||||
flash(_('You did not choose any topics. Would you like to choose individual communities instead?'))
|
||||
return redirect(url_for('main.list_communities'))
|
||||
else:
|
||||
return render_template('topic/choose_topics.html', form=form)
|
||||
|
||||
|
||||
def topics_for_form():
|
||||
topics = Topic.query.order_by(Topic.name).all()
|
||||
result = []
|
||||
for topic in topics:
|
||||
result.append((topic.id, topic.name))
|
||||
return result
|
||||
|
||||
|
||||
def join_topic(topic_id):
|
||||
communities = Community.query.filter_by(topic_id=topic_id, banned=False).all()
|
||||
for community in communities:
|
||||
if not community.user_is_banned(current_user) and community_membership(current_user, community) == SUBSCRIPTION_NONMEMBER:
|
||||
if not community.is_local():
|
||||
join_request = CommunityJoinRequest(user_id=current_user.id, community_id=community.id)
|
||||
db.session.add(join_request)
|
||||
db.session.commit()
|
||||
if current_app.debug:
|
||||
send_community_follow(community.id, join_request)
|
||||
else:
|
||||
send_community_follow.delay(community.id, join_request.id)
|
||||
|
||||
member = CommunityMember(user_id=current_user.id, community_id=community.id)
|
||||
db.session.add(member)
|
||||
db.session.commit()
|
||||
cache.delete_memoized(community_membership, current_user, community)
|
||||
|
||||
|
||||
@celery.task
|
||||
def send_community_follow(community_id, join_request_id):
|
||||
with current_app.app_context():
|
||||
community = Community.query.get(community_id)
|
||||
follow = {
|
||||
"actor": f"https://{current_app.config['SERVER_NAME']}/u/{current_user.user_name}",
|
||||
"to": [community.ap_profile_id],
|
||||
"object": community.ap_profile_id,
|
||||
"type": "Follow",
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/follow/{join_request_id}"
|
||||
}
|
||||
success = post_request(community.ap_inbox_url, follow, current_user.private_key,
|
||||
current_user.profile_id() + '#main-key')
|
|
@ -30,3 +30,5 @@ class Config(object):
|
|||
CELERY_BROKER_URL = os.environ.get('CELERY_BROKER_URL') or 'redis://localhost:6379/0'
|
||||
RESULT_BACKEND = os.environ.get('RESULT_BACKEND') or 'redis://localhost:6379/0'
|
||||
SQLALCHEMY_ECHO = False # set to true to see SQL in console
|
||||
WTF_CSRF_TIME_LIMIT = None # a value of None ensures csrf token is valid for the lifetime of the session
|
||||
|
||||
|
|
34
migrations/versions/52e8d73b69ba_topic_machine_name.py
Normal file
34
migrations/versions/52e8d73b69ba_topic_machine_name.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
"""topic machine name
|
||||
|
||||
Revision ID: 52e8d73b69ba
|
||||
Revises: 86b6fd708bd0
|
||||
Create Date: 2024-01-27 20:40:15.535403
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '52e8d73b69ba'
|
||||
down_revision = '86b6fd708bd0'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('topic', schema=None) as batch_op:
|
||||
batch_op.add_column(sa.Column('machine_name', sa.String(length=50), nullable=True))
|
||||
batch_op.create_index(batch_op.f('ix_topic_machine_name'), ['machine_name'], unique=False)
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('topic', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_topic_machine_name'))
|
||||
batch_op.drop_column('machine_name')
|
||||
|
||||
# ### end Alembic commands ###
|
Loading…
Reference in a new issue