mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 03:16:55 -08:00
comment edit, delete, report, block
This commit is contained in:
parent
8def5b9afc
commit
0b159edf0a
15 changed files with 337 additions and 12 deletions
|
@ -425,7 +425,8 @@ def process_inbox_request(request_json, activitypublog_id):
|
|||
score=instance_weight(user.ap_domain),
|
||||
ap_id=request_json['object']['id'],
|
||||
ap_create_id=request_json['id'],
|
||||
ap_announce_id=None)
|
||||
ap_announce_id=None,
|
||||
instance_id=user.instance_id)
|
||||
if 'source' in request_json['object'] and \
|
||||
request_json['object']['source']['mediaType'] == 'text/markdown':
|
||||
post_reply.body = request_json['object']['source']['content']
|
||||
|
@ -530,7 +531,8 @@ def process_inbox_request(request_json, activitypublog_id):
|
|||
nsfl=community.nsfl,
|
||||
ap_id=request_json['object']['object']['id'],
|
||||
ap_create_id=request_json['object']['id'],
|
||||
ap_announce_id=request_json['id'])
|
||||
ap_announce_id=request_json['id'],
|
||||
instance_id=user.instance_id)
|
||||
if 'source' in request_json['object']['object'] and \
|
||||
request_json['object']['object']['source']['mediaType'] == 'text/markdown':
|
||||
post_reply.body = request_json['object']['object']['source']['content']
|
||||
|
|
|
@ -56,7 +56,7 @@ def register(app):
|
|||
db.create_all()
|
||||
private_key, public_key = RsaKeys.generate_keypair()
|
||||
db.session.add(Site(name="PieFed", description='', public_key=public_key, private_key=private_key))
|
||||
db.session.add(Instance(domain=app.config['SERVER_NAME'], software='PieFed'))
|
||||
db.session.add(Instance(domain=app.config['SERVER_NAME'], software='PieFed')) # Instance 1 is always the local instance
|
||||
db.session.add(Settings(name='allow_nsfw', value=json.dumps(False)))
|
||||
db.session.add(Settings(name='allow_nsfl', value=json.dumps(False)))
|
||||
db.session.add(Settings(name='allow_dislike', value=json.dumps(True)))
|
||||
|
|
|
@ -590,6 +590,7 @@ class PostReply(db.Model):
|
|||
parent_id = db.Column(db.Integer)
|
||||
root_id = db.Column(db.Integer)
|
||||
depth = db.Column(db.Integer, default=0)
|
||||
instance_id = db.Column(db.Integer, db.ForeignKey('instance.id'), index=True)
|
||||
body = db.Column(db.Text)
|
||||
body_html = db.Column(db.Text)
|
||||
body_html_safe = db.Column(db.Boolean, default=False)
|
||||
|
@ -738,6 +739,7 @@ class Instance(db.Model):
|
|||
updated_at = db.Column(db.DateTime, default=utcnow)
|
||||
|
||||
posts = db.relationship('Post', backref='instance', lazy='dynamic')
|
||||
post_replies = db.relationship('PostReply', backref='instance', lazy='dynamic')
|
||||
communities = db.relationship('Community', backref='instance', lazy='dynamic')
|
||||
|
||||
|
||||
|
@ -850,7 +852,6 @@ class Report(db.Model):
|
|||
suspect_user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
|
||||
suspect_post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
|
||||
suspect_post_reply_id = db.Column(db.Integer, db.ForeignKey('post_reply.id'))
|
||||
suspect_reply_id = db.Column(db.Integer, db.ForeignKey('post_reply.id'))
|
||||
created_at = db.Column(db.DateTime, default=utcnow)
|
||||
updated = db.Column(db.DateTime, default=utcnow)
|
||||
|
||||
|
|
|
@ -450,6 +450,13 @@ def post_options(post_id: int):
|
|||
return render_template('post/post_options.html', post=post)
|
||||
|
||||
|
||||
@bp.route('/post/<int:post_id>/comment/<int:comment_id>/options', methods=['GET'])
|
||||
def post_reply_options(post_id: int, comment_id: int):
|
||||
post = Post.query.get_or_404(post_id)
|
||||
post_reply = PostReply.query.get_or_404(comment_id)
|
||||
return render_template('post/post_reply_options.html', post=post, post_reply=post_reply)
|
||||
|
||||
|
||||
@bp.route('/post/<int:post_id>/edit', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def post_edit(post_id: int):
|
||||
|
@ -471,6 +478,7 @@ def post_edit(post_id: int):
|
|||
db.session.commit()
|
||||
post.flush_cache()
|
||||
flash(_('Your changes have been saved.'), 'success')
|
||||
# todo: federate edit
|
||||
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||
else:
|
||||
if post.type == constants.POST_TYPE_ARTICLE:
|
||||
|
@ -513,7 +521,8 @@ def post_report(post_id: int):
|
|||
form = ReportPostForm()
|
||||
if form.validate_on_submit():
|
||||
report = Report(reasons=form.reasons_to_string(form.reasons.data), description=form.description.data,
|
||||
type=1, reporter_id=current_user.id, suspect_post_id=post.id)
|
||||
type=1, reporter_id=current_user.id, suspect_user_id=post.author.id, suspect_post_id=post.id,
|
||||
suspect_community_id=post.community.id)
|
||||
db.session.add(report)
|
||||
|
||||
# Notify moderators
|
||||
|
@ -591,3 +600,118 @@ def post_mea_culpa(post_id: int):
|
|||
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||
|
||||
return render_template('post/post_mea_culpa.html', title=_('I changed my mind'), form=form, post=post)
|
||||
|
||||
|
||||
@bp.route('/post/<int:post_id>/comment/<int:comment_id>/report', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def post_reply_report(post_id: int, comment_id: int):
|
||||
post = Post.query.get_or_404(post_id)
|
||||
post_reply = PostReply.query.get_or_404(comment_id)
|
||||
form = ReportPostForm()
|
||||
if form.validate_on_submit():
|
||||
report = Report(reasons=form.reasons_to_string(form.reasons.data), description=form.description.data,
|
||||
type=1, reporter_id=current_user.id, suspect_post_id=post.id, suspect_community_id=post.community.id,
|
||||
suspect_user_id=post_reply.author.id, suspect_post_reply_id=post_reply.id)
|
||||
db.session.add(report)
|
||||
|
||||
# Notify moderators
|
||||
for mod in post.community.moderators():
|
||||
notification = Notification(user_id=mod.user_id, title=_('A comment has been reported'),
|
||||
url=f"https://{current_app.config['SERVER_NAME']}/comment/{post_reply.id}",
|
||||
author_id=current_user.id)
|
||||
db.session.add(notification)
|
||||
post_reply.reports += 1
|
||||
# todo: Also notify admins for certain types of report
|
||||
db.session.commit()
|
||||
|
||||
# todo: federate report to originating instance
|
||||
if not post.community.is_local() and form.report_remote.data:
|
||||
...
|
||||
|
||||
flash(_('Comment has been reported, thank you!'))
|
||||
return redirect(post.community.local_url())
|
||||
elif request.method == 'GET':
|
||||
form.report_remote.data = True
|
||||
|
||||
return render_template('post/post_reply_report.html', title=_('Report comment'), form=form, post=post, post_reply=post_reply)
|
||||
|
||||
|
||||
@bp.route('/post/<int:post_id>/comment/<int:comment_id>/block_user', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def post_reply_block_user(post_id: int, comment_id: int):
|
||||
post = Post.query.get_or_404(post_id)
|
||||
post_reply = PostReply.query.get_or_404(comment_id)
|
||||
existing = UserBlock.query.filter_by(blocker_id=current_user.id, blocked_id=post_reply.author.id).first()
|
||||
if not existing:
|
||||
db.session.add(UserBlock(blocker_id=current_user.id, blocked_id=post_reply.author.id))
|
||||
db.session.commit()
|
||||
flash(_('%(name)s has been blocked.', name=post_reply.author.user_name))
|
||||
|
||||
# todo: federate block to post_reply author instance
|
||||
|
||||
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||
|
||||
|
||||
@bp.route('/post/<int:post_id>/comment/<int:comment_id>/block_instance', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def post_reply_block_instance(post_id: int, comment_id: int):
|
||||
post = Post.query.get_or_404(post_id)
|
||||
post_reply = PostReply.query.get_or_404(comment_id)
|
||||
existing = InstanceBlock.query.filter_by(user_id=current_user.id, instance_id=post_reply.instance_id).first()
|
||||
if not existing:
|
||||
db.session.add(InstanceBlock(user_id=current_user.id, instance_id=post_reply.instance_id))
|
||||
db.session.commit()
|
||||
flash(_('Content from %(name)s will be hidden.', name=post_reply.instance.domain))
|
||||
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||
|
||||
|
||||
@bp.route('/post/<int:post_id>/comment/<int:comment_id>/edit', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def post_reply_edit(post_id: int, comment_id: int):
|
||||
post = Post.query.get_or_404(post_id)
|
||||
post_reply = PostReply.query.get_or_404(comment_id)
|
||||
if post_reply.parent_id:
|
||||
comment = PostReply.query.get_or_404(post_reply.parent_id)
|
||||
else:
|
||||
comment = None
|
||||
form = NewReplyForm()
|
||||
if post_reply.user_id == current_user.id or post.community.is_moderator():
|
||||
if form.validate_on_submit():
|
||||
post_reply.body = form.body.data
|
||||
post_reply.body_html = markdown_to_html(form.body.data)
|
||||
post_reply.notify_author = form.notify_author.data
|
||||
post.community.last_active = utcnow()
|
||||
post_reply.edited_at = utcnow()
|
||||
db.session.commit()
|
||||
post.flush_cache()
|
||||
flash(_('Your changes have been saved.'), 'success')
|
||||
# todo: federate edit
|
||||
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||
else:
|
||||
form.body.data = post_reply.body
|
||||
form.notify_author.data = not post_reply.notify_author
|
||||
return render_template('post/post_reply_edit.html', title=_('Edit comment'), form=form, post=post, post_reply=post_reply,
|
||||
comment=comment, markdown_editor=True)
|
||||
else:
|
||||
abort(401)
|
||||
|
||||
|
||||
@bp.route('/post/<int:post_id>/comment/<int:comment_id>/delete', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def post_reply_delete(post_id: int, comment_id: int):
|
||||
post = Post.query.get_or_404(post_id)
|
||||
post_reply = PostReply.query.get_or_404(comment_id)
|
||||
community = post.community
|
||||
if post_reply.user_id == current_user.id or community.is_moderator():
|
||||
if post_reply.has_replies():
|
||||
post_reply.body = 'Deleted by author' if post_reply.author.id == current_user.id else 'Deleted by moderator'
|
||||
post_reply.body_html = markdown_to_html(post_reply.body)
|
||||
else:
|
||||
post_reply.delete_dependencies()
|
||||
db.session.delete(post_reply)
|
||||
g.site.last_active = community.last_active = utcnow()
|
||||
db.session.commit()
|
||||
post.flush_cache()
|
||||
flash(_('Comment deleted.'))
|
||||
# todo: federate delete
|
||||
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
|
@ -618,6 +618,7 @@ fieldset legend {
|
|||
}
|
||||
.comment .comment_actions {
|
||||
margin-top: -10px;
|
||||
position: relative;
|
||||
}
|
||||
.comment .comment_actions a {
|
||||
text-decoration: none;
|
||||
|
|
|
@ -337,6 +337,7 @@ nav, etc which are used site-wide */
|
|||
|
||||
.comment_actions {
|
||||
margin-top: -10px;
|
||||
position: relative;
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
|
|
@ -545,6 +545,15 @@ nav.navbar {
|
|||
text-decoration: none;
|
||||
}
|
||||
|
||||
.comment_actions_link {
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 48px;
|
||||
width: 41px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.alert {
|
||||
width: 96%;
|
||||
}
|
||||
|
|
|
@ -241,6 +241,15 @@ nav.navbar {
|
|||
text-decoration: none;
|
||||
}
|
||||
|
||||
.comment_actions_link {
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 48px;
|
||||
width: 41px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.alert {
|
||||
width: 96%;
|
||||
}
|
||||
|
|
|
@ -89,13 +89,14 @@
|
|||
{{ comment['comment'].body_html | safe }}
|
||||
</div>
|
||||
</div>
|
||||
{% if current_user.is_authenticated and current_user.verified %}
|
||||
<div class="comment_actions hidable">
|
||||
<div class="comment_actions hidable">
|
||||
{% if current_user.is_authenticated and current_user.verified %}
|
||||
{% if post.comments_enabled %}
|
||||
<a href="{{ url_for('post.add_reply', post_id=post.id, comment_id=comment['comment'].id) }}" rel="nofollow"><span class="fe fe-reply"></span> reply</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<a href="{{ url_for('post.post_reply_options', post_id=post.id, comment_id=comment['comment'].id) }}" class="comment_actions_link" rel="nofollow"><span class="fe fe-options" title="Options"> </span></a>
|
||||
</div>
|
||||
{% if comment['replies'] %}
|
||||
{% if comment['comment'].depth <= THREAD_CUTOFF_DEPTH %}
|
||||
<div class="replies hidable">
|
||||
|
|
|
@ -26,16 +26,16 @@
|
|||
<li><a href="{{ url_for('post.post_block_domain', post_id=post.id) }}" class="no-underline"><span class="fe fe-block"></span>
|
||||
{{ _('Block domain %(domain)s', domain=post.domain.name) }}</a></li>
|
||||
{% endif %}
|
||||
{% if post.instance_id %}
|
||||
{% if post.instance_id and post.instance_id != 1 %}
|
||||
<li><a href="{{ url_for('post.post_block_instance', post_id=post.id) }}" class="no-underline"><span class="fe fe-block"></span>
|
||||
{{ _('Hide every post from %(name)s', name=post.instance.domain) }}</a></li>
|
||||
{{ _("Hide every post from author's instance: %(name)s", name=post.instance.domain) }}</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<li><a href="{{ url_for('post.post_report', post_id=post.id) }}" class="no-underline"><span class="fe fe-report"></span>
|
||||
{{ _('Report to moderators') }}</a></li>
|
||||
|
||||
{% endif %}
|
||||
</ul>
|
||||
<p>{{ _('If you want to perform more than one of these (e.g. block and report), hold down Ctrl and click, then complete the operation in the new tabs that open.') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
85
app/templates/post/post_reply_edit.html
Normal file
85
app/templates/post/post_reply_edit.html
Normal file
|
@ -0,0 +1,85 @@
|
|||
{% extends "base.html" %}
|
||||
{% from 'bootstrap/form.html' import render_form %}
|
||||
|
||||
{% block app_content %}
|
||||
<script src="/static/js/coolfieldset.js"></script>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-8 position-relative add_reply main_pane">
|
||||
<fieldset class="coolfieldset mt-4"><legend class="w-auto">Original post</legend>
|
||||
<h3>{{ post.title }}</h3>
|
||||
{{ post.body_html | safe }}
|
||||
</fieldset>
|
||||
{% if comment %}
|
||||
<fieldset class="coolfieldset mt-4"><legend class="w-auto">Comment you are replying to</legend>
|
||||
{{ comment.body_html | safe}}
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
<div class="position-relative">
|
||||
{{ render_form(form) }}
|
||||
{% if markdown_editor %}
|
||||
<script nonce="{{ session['nonce'] }}">
|
||||
window.addEventListener("load", function () {
|
||||
var downarea = new DownArea({
|
||||
elem: document.querySelector('#body'),
|
||||
resize: DownArea.RESIZE_VERTICAL,
|
||||
hide: ['heading', 'bold-italic'],
|
||||
value: {{ form.body.data | tojson | safe }}
|
||||
});
|
||||
setupAutoResize('body');
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
{% if current_user.is_authenticated and community_membership(current_user, post.community) %}
|
||||
<a class="w-100 btn btn-primary" href="/community/{{ post.community.link() }}/unsubscribe">{{ _('Unsubscribe') }}</a>
|
||||
{% else %}
|
||||
<a class="w-100 btn btn-primary" href="/community/{{ post.community.link() }}/subscribe">{{ _('Subscribe') }}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<a class="w-100 btn btn-primary" href="/community/{{ post.community.link() }}/submit">{{ _('Create post') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
<form method="get">
|
||||
<input type="search" name="search" class="form-control mt-2" placeholder="{{ _('Search this community') }}" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">
|
||||
<h2>{{ _('About community') }}</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>{{ post.community.description|safe }}</p>
|
||||
<p>{{ post.community.rules|safe }}</p>
|
||||
{% if len(mods) > 0 and not post.community.private_mods %}
|
||||
<h3>Moderators</h3>
|
||||
<ol>
|
||||
{% for mod in mods %}
|
||||
<li><a href="/u/{{ mod.user_name }}">{{ mod.user_name }}</a></li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if is_moderator %}
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">
|
||||
<h2>{{ _('Community Settings') }}</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><a href="#" class="btn btn-primary">{{ _('Moderate') }}</a></p>
|
||||
<p><a href="#" class="btn btn-primary">{{ _('Settings') }}</a></p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
36
app/templates/post/post_reply_options.html
Normal file
36
app/templates/post/post_reply_options.html
Normal file
|
@ -0,0 +1,36 @@
|
|||
{% 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">
|
||||
<div class="card-title">{{ _('Options for comment on "%(post_title)s"', post_title=post.title) }}</div>
|
||||
<ul class="option_list">
|
||||
{% if current_user.is_authenticated %}
|
||||
{% if post_reply.user_id == current_user.id or post.community.is_moderator() %}
|
||||
<li><a href="{{ url_for('post.post_reply_edit', post_id=post.id, comment_id=post_reply.id) }}" class="no-underline" rel="nofollow"><span class="fe fe-edit"></span>
|
||||
{{ _('Edit') }}</a></li>
|
||||
<li><a href="{{ url_for('post.post_reply_delete', post_id=post.id, comment_id=post_reply.id) }}" class="no-underline confirm_first" rel="nofollow"><span class="fe fe-delete"></span>
|
||||
{{ _('Delete') }}</a></li>
|
||||
{% endif %}
|
||||
{% if post_reply.user_id != current_user.id %}
|
||||
<li><a href="{{ url_for('post.post_reply_block_user', post_id=post.id, comment_id=post_reply.id) }}" class="no-underline"><span class="fe fe-block"></span>
|
||||
{{ _('Block author @%(author_name)s', author_name=post_reply.author.user_name) }}</a></li>
|
||||
{% if post_reply.instance_id and post_reply.instance_id != 1 %}
|
||||
<li><a href="{{ url_for('post.post_reply_block_instance', post_id=post.id, comment_id=post_reply.id) }}" class="no-underline"><span class="fe fe-block"></span>
|
||||
{{ _("Hide every post from author's instance: %(name)s", name=post_reply.instance.domain) }}</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<li><a href="{{ url_for('post.post_reply_report', post_id=post.id, comment_id=post_reply.id) }}" class="no-underline"><span class="fe fe-report"></span>
|
||||
{{ _('Report to moderators') }}</a></li>
|
||||
|
||||
{% endif %}
|
||||
</ul>
|
||||
<p>{{ _('If you want to perform more than one of these (e.g. block and report), hold down Ctrl and click, then complete the operation in the new tabs that open.') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
18
app/templates/post/post_reply_report.html
Normal file
18
app/templates/post/post_reply_report.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
{% 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">
|
||||
<div class="card-title">{{ _('Report comment on "%(post_title)s" by %(reply_name)s',
|
||||
post_title=post.title, reply_name=post_reply.author.user_name) }}</div>
|
||||
<div class="card-body">
|
||||
{{ render_form(form) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
36
migrations/versions/e8113bc01e3a_post_reply_instance.py
Normal file
36
migrations/versions/e8113bc01e3a_post_reply_instance.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
"""post reply instance
|
||||
|
||||
Revision ID: e8113bc01e3a
|
||||
Revises: 52789c4b1d0f
|
||||
Create Date: 2023-12-28 13:11:04.462308
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'e8113bc01e3a'
|
||||
down_revision = '52789c4b1d0f'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('post_reply', schema=None) as batch_op:
|
||||
batch_op.add_column(sa.Column('instance_id', sa.Integer(), nullable=True))
|
||||
batch_op.create_index(batch_op.f('ix_post_reply_instance_id'), ['instance_id'], unique=False)
|
||||
batch_op.create_foreign_key(None, 'instance', ['instance_id'], ['id'])
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('post_reply', schema=None) as batch_op:
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.drop_index(batch_op.f('ix_post_reply_instance_id'))
|
||||
batch_op.drop_column('instance_id')
|
||||
|
||||
# ### end Alembic commands ###
|
2
regional.txt
Normal file
2
regional.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
africa
|
||||
https://baraza.africa/c/africa
|
Loading…
Reference in a new issue