mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 11:26:56 -08:00
community setting: accept downvotes from community members only
This commit is contained in:
parent
57da9f7182
commit
cb7d4fc40f
7 changed files with 86 additions and 5 deletions
|
@ -8,6 +8,8 @@ from wtforms.validators import ValidationError, DataRequired, Email, EqualTo, Le
|
||||||
from flask_babel import _, lazy_gettext as _l
|
from flask_babel import _, lazy_gettext as _l
|
||||||
|
|
||||||
from app import db
|
from app import db
|
||||||
|
from app.constants import DOWNVOTE_ACCEPT_ALL, DOWNVOTE_ACCEPT_MEMBERS, DOWNVOTE_ACCEPT_INSTANCE, \
|
||||||
|
DOWNVOTE_ACCEPT_TRUSTED
|
||||||
from app.models import Community, utcnow
|
from app.models import Community, utcnow
|
||||||
from app.utils import domain_from_url, MultiCheckboxField
|
from app.utils import domain_from_url, MultiCheckboxField
|
||||||
from PIL import Image, ImageOps
|
from PIL import Image, ImageOps
|
||||||
|
@ -54,6 +56,13 @@ class EditCommunityForm(FlaskForm):
|
||||||
local_only = BooleanField(_l('Only accept posts from current instance'))
|
local_only = BooleanField(_l('Only accept posts from current instance'))
|
||||||
restricted_to_mods = BooleanField(_l('Only moderators can post'))
|
restricted_to_mods = BooleanField(_l('Only moderators can post'))
|
||||||
new_mods_wanted = BooleanField(_l('New moderators wanted'))
|
new_mods_wanted = BooleanField(_l('New moderators wanted'))
|
||||||
|
downvote_accept_modes = [(DOWNVOTE_ACCEPT_ALL, _l('Everyone')),
|
||||||
|
(DOWNVOTE_ACCEPT_MEMBERS, _l('Community members')),
|
||||||
|
(DOWNVOTE_ACCEPT_INSTANCE, _l('This instance')),
|
||||||
|
(DOWNVOTE_ACCEPT_TRUSTED, _l('Trusted instances')),
|
||||||
|
|
||||||
|
]
|
||||||
|
downvote_accept_mode = SelectField(_l('Accept downvotes from'), coerce=int, choices=downvote_accept_modes, validators=[Optional()], render_kw={'class': 'form-select'})
|
||||||
topic = SelectField(_l('Topic'), coerce=int, validators=[Optional()], render_kw={'class': 'form-select'})
|
topic = SelectField(_l('Topic'), coerce=int, validators=[Optional()], render_kw={'class': 'form-select'})
|
||||||
languages = SelectMultipleField(_l('Languages'), coerce=int, validators=[Optional()], render_kw={'class': 'form-select'})
|
languages = SelectMultipleField(_l('Languages'), coerce=int, validators=[Optional()], render_kw={'class': 'form-select'})
|
||||||
layouts = [('', _l('List')),
|
layouts = [('', _l('List')),
|
||||||
|
|
|
@ -1019,6 +1019,7 @@ def community_edit(community_id: int):
|
||||||
community.new_mods_wanted = form.new_mods_wanted.data
|
community.new_mods_wanted = form.new_mods_wanted.data
|
||||||
community.topic_id = form.topic.data if form.topic.data != 0 else None
|
community.topic_id = form.topic.data if form.topic.data != 0 else None
|
||||||
community.default_layout = form.default_layout.data
|
community.default_layout = form.default_layout.data
|
||||||
|
community.downvote_accept_mode = form.downvote_accept_mode.data
|
||||||
|
|
||||||
icon_file = request.files['icon_file']
|
icon_file = request.files['icon_file']
|
||||||
if icon_file and icon_file.filename != '':
|
if icon_file and icon_file.filename != '':
|
||||||
|
@ -1067,6 +1068,7 @@ def community_edit(community_id: int):
|
||||||
form.topic.data = community.topic_id if community.topic_id else None
|
form.topic.data = community.topic_id if community.topic_id else None
|
||||||
form.languages.data = community.language_ids()
|
form.languages.data = community.language_ids()
|
||||||
form.default_layout.data = community.default_layout
|
form.default_layout.data = community.default_layout
|
||||||
|
form.downvote_accept_mode.data = community.downvote_accept_mode
|
||||||
return render_template('community/community_edit.html', title=_('Edit community'), form=form,
|
return render_template('community/community_edit.html', title=_('Edit community'), form=form,
|
||||||
current_app=current_app, current="edit_settings",
|
current_app=current_app, current="edit_settings",
|
||||||
community=community, moderating_communities=moderating_communities(current_user.get_id()),
|
community=community, moderating_communities=moderating_communities(current_user.get_id()),
|
||||||
|
|
|
@ -35,6 +35,11 @@ NOTIF_REPLY = 4
|
||||||
ROLE_STAFF = 3
|
ROLE_STAFF = 3
|
||||||
ROLE_ADMIN = 4
|
ROLE_ADMIN = 4
|
||||||
|
|
||||||
|
DOWNVOTE_ACCEPT_ALL = 0
|
||||||
|
DOWNVOTE_ACCEPT_MEMBERS = 2
|
||||||
|
DOWNVOTE_ACCEPT_INSTANCE = 4
|
||||||
|
DOWNVOTE_ACCEPT_TRUSTED = 6
|
||||||
|
|
||||||
MICROBLOG_APPS = ["mastodon", "misskey", "akkoma", "iceshrimp", "pleroma"]
|
MICROBLOG_APPS = ["mastodon", "misskey", "akkoma", "iceshrimp", "pleroma"]
|
||||||
|
|
||||||
APLOG_IN = True
|
APLOG_IN = True
|
||||||
|
|
|
@ -75,7 +75,7 @@ class Instance(db.Model):
|
||||||
start_trying_again = db.Column(db.DateTime) # When to start trying again. Should grow exponentially with each failure.
|
start_trying_again = db.Column(db.DateTime) # When to start trying again. Should grow exponentially with each failure.
|
||||||
gone_forever = db.Column(db.Boolean, default=False) # True once this instance is considered offline forever - never start trying again
|
gone_forever = db.Column(db.Boolean, default=False) # True once this instance is considered offline forever - never start trying again
|
||||||
ip_address = db.Column(db.String(50))
|
ip_address = db.Column(db.String(50))
|
||||||
trusted = db.Column(db.Boolean, default=False)
|
trusted = db.Column(db.Boolean, default=False, index=True)
|
||||||
posting_warning = db.Column(db.String(512))
|
posting_warning = db.Column(db.String(512))
|
||||||
nodeinfo_href = db.Column(db.String(100))
|
nodeinfo_href = db.Column(db.String(100))
|
||||||
|
|
||||||
|
@ -438,6 +438,7 @@ class Community(db.Model):
|
||||||
topic_id = db.Column(db.Integer, db.ForeignKey('topic.id'), index=True)
|
topic_id = db.Column(db.Integer, db.ForeignKey('topic.id'), index=True)
|
||||||
default_layout = db.Column(db.String(15))
|
default_layout = db.Column(db.String(15))
|
||||||
posting_warning = db.Column(db.String(512))
|
posting_warning = db.Column(db.String(512))
|
||||||
|
downvote_accept_mode = db.Column(db.Integer, default=0) # 0 = All, 2 = Community members, 4 = This instance, 6 = Trusted instances
|
||||||
|
|
||||||
ap_id = db.Column(db.String(255), index=True)
|
ap_id = db.Column(db.String(255), index=True)
|
||||||
ap_profile_id = db.Column(db.String(255), index=True, unique=True)
|
ap_profile_id = db.Column(db.String(255), index=True, unique=True)
|
||||||
|
|
|
@ -59,20 +59,22 @@
|
||||||
{{ render_field(form.restricted_to_mods) }}
|
{{ render_field(form.restricted_to_mods) }}
|
||||||
{{ render_field(form.local_only) }}
|
{{ render_field(form.local_only) }}
|
||||||
{{ render_field(form.new_mods_wanted) }}
|
{{ render_field(form.new_mods_wanted) }}
|
||||||
|
{{ render_field(form.downvote_accept_mode) }}
|
||||||
{{ render_field(form.topic) }}
|
{{ render_field(form.topic) }}
|
||||||
{{ render_field(form.languages) }}
|
{{ render_field(form.languages) }}
|
||||||
{{ render_field(form.default_layout) }}
|
{{ render_field(form.default_layout) }}
|
||||||
<div class="row">
|
<div class="row mb-4">
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
{{ render_field(form.submit) }}
|
{{ render_field(form.submit) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-auto pt-4">
|
||||||
{% if community.is_local() and (community.is_owner() or current_user.is_admin()) %}
|
{% if community.is_local() and (community.is_owner() or current_user.is_admin()) %}
|
||||||
<p><a class="btn btn-primary btn-warning" href="{{ url_for('community.community_delete', community_id=community.id) }}" rel="nofollow">Delete community</a></p>
|
<p><a class="btn btn-primary btn-warning" href="{{ url_for('community.community_delete', community_id=community.id) }}" rel="nofollow">Delete community</a></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
21
app/utils.py
21
app/utils.py
|
@ -19,6 +19,8 @@ from bs4 import BeautifulSoup, MarkupResemblesLocatorWarning
|
||||||
import warnings
|
import warnings
|
||||||
import jwt
|
import jwt
|
||||||
|
|
||||||
|
from app.constants import DOWNVOTE_ACCEPT_ALL, DOWNVOTE_ACCEPT_TRUSTED, DOWNVOTE_ACCEPT_INSTANCE, \
|
||||||
|
DOWNVOTE_ACCEPT_MEMBERS
|
||||||
|
|
||||||
warnings.filterwarnings("ignore", category=MarkupResemblesLocatorWarning)
|
warnings.filterwarnings("ignore", category=MarkupResemblesLocatorWarning)
|
||||||
import os
|
import os
|
||||||
|
@ -715,6 +717,20 @@ def can_downvote(user, community: Community, site=None) -> bool:
|
||||||
if (user.attitude and user.attitude < -0.40) or user.reputation < -10: # this should exclude about 3.7% of users.
|
if (user.attitude and user.attitude < -0.40) or user.reputation < -10: # this should exclude about 3.7% of users.
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if community.downvote_accept_mode != DOWNVOTE_ACCEPT_ALL:
|
||||||
|
if community.downvote_accept_mode == DOWNVOTE_ACCEPT_MEMBERS:
|
||||||
|
if not community.is_member(user):
|
||||||
|
return False
|
||||||
|
elif community.downvote_accept_mode == DOWNVOTE_ACCEPT_INSTANCE:
|
||||||
|
if user.instance_id != community.instance_id:
|
||||||
|
return False
|
||||||
|
elif community.downvote_accept_mode == DOWNVOTE_ACCEPT_TRUSTED:
|
||||||
|
if community.instance_id == user.instance_id:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if user.instance_id not in trusted_instance_ids():
|
||||||
|
return False
|
||||||
|
|
||||||
if community.id in communities_banned_from(user.id):
|
if community.id in communities_banned_from(user.id):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -812,6 +828,11 @@ def reply_is_stupid(body) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@cache.memoize(timeout=10)
|
||||||
|
def trusted_instance_ids() -> List[int]:
|
||||||
|
return [instance.id for instance in Instance.query.filter(Instance.trusted == True)]
|
||||||
|
|
||||||
|
|
||||||
def inbox_domain(inbox: str) -> str:
|
def inbox_domain(inbox: str) -> str:
|
||||||
inbox = inbox.lower()
|
inbox = inbox.lower()
|
||||||
if 'https://' in inbox or 'http://' in inbox:
|
if 'https://' in inbox or 'http://' in inbox:
|
||||||
|
|
41
migrations/versions/03258111eef1_downvote_accept_mode.py
Normal file
41
migrations/versions/03258111eef1_downvote_accept_mode.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
"""downvote accept mode
|
||||||
|
|
||||||
|
Revision ID: 03258111eef1
|
||||||
|
Revises: 9df13396fd54
|
||||||
|
Create Date: 2025-01-11 11:32:54.226698
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '03258111eef1'
|
||||||
|
down_revision = '9df13396fd54'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('community', schema=None) as batch_op:
|
||||||
|
batch_op.add_column(sa.Column('downvote_accept_mode', sa.Integer(), nullable=True))
|
||||||
|
|
||||||
|
with op.batch_alter_table('community', schema=None) as batch_op:
|
||||||
|
batch_op.execute('UPDATE "community" SET downvote_accept_mode = 0')
|
||||||
|
|
||||||
|
with op.batch_alter_table('instance', schema=None) as batch_op:
|
||||||
|
batch_op.create_index(batch_op.f('ix_instance_trusted'), ['trusted'], unique=False)
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('instance', schema=None) as batch_op:
|
||||||
|
batch_op.drop_index(batch_op.f('ix_instance_trusted'))
|
||||||
|
|
||||||
|
with op.batch_alter_table('community', schema=None) as batch_op:
|
||||||
|
batch_op.drop_column('downvote_accept_mode')
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
Loading…
Reference in a new issue