flag low effort commenters

This commit is contained in:
rimu 2024-05-21 22:20:08 +12:00
parent fa953ba976
commit 709980c6f3
13 changed files with 90 additions and 6 deletions

View file

@ -1426,6 +1426,8 @@ def create_post_reply(activity_log: ActivityPubLog, community: Community, in_rep
post_reply.ranking = confidence(post_reply.up_votes, post_reply.down_votes) post_reply.ranking = confidence(post_reply.up_votes, post_reply.down_votes)
db.session.commit() db.session.commit()
user.recalculate_avg_comment_length()
# send notification to the post/comment being replied to # send notification to the post/comment being replied to
if parent_comment_id: if parent_comment_id:
notify_about_post_reply(parent_comment, post_reply) notify_about_post_reply(parent_comment, post_reply)

View file

@ -3,9 +3,10 @@ from time import time
from typing import List, Union from typing import List, Union
import requests import requests
from bs4 import BeautifulSoup
from flask import current_app, escape, url_for, render_template_string from flask import current_app, escape, url_for, render_template_string
from flask_login import UserMixin, current_user from flask_login import UserMixin, current_user
from sqlalchemy import or_, text from sqlalchemy import or_, text, desc
from werkzeug.security import generate_password_hash, check_password_hash from werkzeug.security import generate_password_hash, check_password_hash
from flask_babel import _, lazy_gettext as _l from flask_babel import _, lazy_gettext as _l
from sqlalchemy.orm import backref from sqlalchemy.orm import backref
@ -615,6 +616,8 @@ class User(UserMixin, db.Model):
markdown_editor = db.Column(db.Boolean, default=False) markdown_editor = db.Column(db.Boolean, default=False)
interface_language = db.Column(db.String(10)) # a locale that the translation system understands e.g. 'en' or 'en-us'. If empty, use browser default interface_language = db.Column(db.String(10)) # a locale that the translation system understands e.g. 'en' or 'en-us'. If empty, use browser default
language_id = db.Column(db.Integer, db.ForeignKey('language.id')) # the default choice in the language dropdown when composing posts & comments language_id = db.Column(db.Integer, db.ForeignKey('language.id')) # the default choice in the language dropdown when composing posts & comments
average_comment_length = db.Column(db.Integer)
comment_length_warning = db.Column(db.Integer, default=15)
avatar = db.relationship('File', lazy='joined', foreign_keys=[avatar_id], single_parent=True, cascade="all, delete-orphan") avatar = db.relationship('File', lazy='joined', foreign_keys=[avatar_id], single_parent=True, cascade="all, delete-orphan")
cover = db.relationship('File', lazy='joined', foreign_keys=[cover_id], single_parent=True, cascade="all, delete-orphan") cover = db.relationship('File', lazy='joined', foreign_keys=[cover_id], single_parent=True, cascade="all, delete-orphan")
@ -808,6 +811,19 @@ class User(UserMixin, db.Model):
else: else:
self.attitude = (total_upvotes - total_downvotes) / (total_upvotes + total_downvotes) self.attitude = (total_upvotes - total_downvotes) / (total_upvotes + total_downvotes)
def recalculate_avg_comment_length(self):
replies = db.session.execute(text('SELECT body, body_html FROM "post_reply" WHERE user_id = :user_id ORDER BY created_at DESC LIMIT 30'),
{'user_id': self.id}).all()
lengths = []
for reply in replies:
if reply.body.strip() != '':
lengths.append(len(reply.body.strip()))
else:
soup = BeautifulSoup(reply.body_html, 'html.parser')
lengths.append(len(soup.get_text()))
if len(lengths) > 5:
self.average_comment_length = math.ceil(sum(lengths) / len(lengths))
def subscribed(self, community_id: int) -> int: def subscribed(self, community_id: int) -> int:
if community_id is None: if community_id is None:
return False return False

View file

@ -111,6 +111,8 @@ def show_post(post_id: int):
db.session.add(reply) db.session.add(reply)
db.session.commit() db.session.commit()
current_user.recalculate_avg_comment_length()
notify_about_post_reply(None, reply) notify_about_post_reply(None, reply)
# Subscribe to own comment # Subscribe to own comment
@ -671,6 +673,8 @@ def add_reply(post_id: int, comment_id: int):
db.session.add(reply) db.session.add(reply)
db.session.commit() db.session.commit()
current_user.recalculate_avg_comment_length()
# Notify subscribers # Notify subscribers
notify_about_post_reply(in_reply_to, reply) notify_about_post_reply(in_reply_to, reply)

View file

@ -15,3 +15,7 @@ $super-dark-grey: #424549;
.orangered { .orangered {
color: orangered; color: orangered;
} }
.purple {
color: purple;
}

View file

@ -8,6 +8,10 @@ nav, etc which are used site-wide */
color: orangered; color: orangered;
} }
.purple {
color: purple;
}
.pl-0 { .pl-0 {
padding-left: 0 !important; padding-left: 0 !important;
} }

View file

@ -7,6 +7,10 @@
color: orangered; color: orangered;
} }
.purple {
color: purple;
}
.pl-0 { .pl-0 {
padding-left: 0 !important; padding-left: 0 !important;
} }

View file

@ -138,7 +138,9 @@
</div> </div>
{% if post.type == POST_TYPE_POLL %} {% if post.type == POST_TYPE_POLL %}
<div class="post_poll"> <div class="post_poll">
{% if poll_results %} {% if poll_results and poll_total_votes == 0 %}
<p>{{ _('The poll has finished, yet no votes were cast.') }}</p>
{% elif poll_results and poll_total_votes %}
<ul> <ul>
{% for choice in poll_choices %} {% for choice in poll_choices %}
<li> <li>

View file

@ -100,6 +100,9 @@
{% elif comment['comment'].author.reputation < 0 %} {% elif comment['comment'].author.reputation < 0 %}
<span class="fe fe-warning orangered" title="Low reputation."> </span> <span class="fe fe-warning orangered" title="Low reputation."> </span>
{% endif %} {% endif %}
{% if current_user.is_authenticated and current_user.comment_length_warning and comment['comment'].author.average_comment_length and comment['comment'].author.average_comment_length <= current_user.comment_length_warning %}
<span class="fe fe-warning purple" title="{{ _('Usually makes short and low effort comments.') }}"> </span>
{% endif %}
{% endif %} {% endif %}
{% if comment['comment'].author.id == post.author.id %}<span title="Submitter of original post" aria-label="{{ _('Post creator') }}" class="small">[OP]</span>{% endif %} {% if comment['comment'].author.id == post.author.id %}<span title="Submitter of original post" aria-label="{{ _('Post creator') }}" class="small">[OP]</span>{% endif %}
<span class="text-muted small" aria_label="{{ _('When: ') }}">{{ moment(comment['comment'].posted_at).fromNow(refresh=True) }}{% if comment['comment'].edited_at %}, edited {{ moment(comment['comment'].edited_at).fromNow(refresh=True) }} {% endif %}</span> <span class="text-muted small" aria_label="{{ _('When: ') }}">{{ moment(comment['comment'].posted_at).fromNow(refresh=True) }}{% if comment['comment'].edited_at %}, edited {{ moment(comment['comment'].edited_at).fromNow(refresh=True) }} {% endif %}</span>

View file

@ -35,6 +35,8 @@
{{ render_field(form.markdown_editor) }} {{ render_field(form.markdown_editor) }}
{{ render_field(form.default_sort) }} {{ render_field(form.default_sort) }}
{{ render_field(form.theme) }} {{ render_field(form.theme) }}
{{ render_field(form.comment_length_warning) }}
<small class="field_hint">{{ _('Accounts which usually post comments shorter than this will have a warning. Set to 0 to disable warning.') }}</small>
<h5>Import</h5> <h5>Import</h5>
{{ render_field(form.import_file) }} {{ render_field(form.import_file) }}
{{ render_field(form.submit) }} {{ render_field(form.submit) }}

View file

@ -2,7 +2,7 @@ from flask import session
from flask_login import current_user from flask_login import current_user
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, PasswordField, BooleanField, EmailField, TextAreaField, FileField, \ from wtforms import StringField, SubmitField, PasswordField, BooleanField, EmailField, TextAreaField, FileField, \
RadioField, DateField, SelectField RadioField, DateField, SelectField, IntegerField
from wtforms.fields.choices import SelectMultipleField from wtforms.fields.choices import SelectMultipleField
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo, Length, Optional from wtforms.validators import ValidationError, DataRequired, Email, EqualTo, Length, Optional
from flask_babel import _, lazy_gettext as _l from flask_babel import _, lazy_gettext as _l
@ -50,6 +50,7 @@ class SettingsForm(FlaskForm):
] ]
default_sort = SelectField(_l('By default, sort posts by'), choices=sorts, validators=[DataRequired()], coerce=str, render_kw={'class': 'form-select'}) default_sort = SelectField(_l('By default, sort posts by'), choices=sorts, validators=[DataRequired()], coerce=str, render_kw={'class': 'form-select'})
theme = SelectField(_l('Theme'), coerce=str, render_kw={'class': 'form-select'}) theme = SelectField(_l('Theme'), coerce=str, render_kw={'class': 'form-select'})
comment_length_warning = IntegerField(_('Useless comment cutoff length'))
submit = SubmitField(_l('Save settings')) submit = SubmitField(_l('Save settings'))

View file

@ -188,6 +188,7 @@ def change_settings():
current_user.email_unread = form.email_unread.data current_user.email_unread = form.email_unread.data
current_user.markdown_editor = form.markdown_editor.data current_user.markdown_editor = form.markdown_editor.data
current_user.interface_language = form.interface_language.data current_user.interface_language = form.interface_language.data
current_user.comment_length_warning = form.comment_length_warning.data
session['ui_language'] = form.interface_language.data session['ui_language'] = form.interface_language.data
import_file = request.files['import_file'] import_file = request.files['import_file']
if propagate_indexable: if propagate_indexable:
@ -227,6 +228,7 @@ def change_settings():
form.theme.data = current_user.theme form.theme.data = current_user.theme
form.markdown_editor.data = current_user.markdown_editor form.markdown_editor.data = current_user.markdown_editor
form.interface_language.data = current_user.interface_language form.interface_language.data = current_user.interface_language
form.comment_length_warning.data = current_user.comment_length_warning
return render_template('user/edit_settings.html', title=_('Edit profile'), form=form, user=current_user, return render_template('user/edit_settings.html', title=_('Edit profile'), form=form, user=current_user,
moderating_communities=moderating_communities(current_user.get_id()), moderating_communities=moderating_communities(current_user.get_id()),

View file

@ -258,6 +258,13 @@ def markdown_to_text(markdown_text) -> str:
return markdown_text.replace("# ", '') return markdown_text.replace("# ", '')
def html_to_text(html) -> str:
if html is None or html == '':
return ''
soup = BeautifulSoup(html, 'html.parser')
return soup.get_text()
def microblog_content_to_title(html: str) -> str: def microblog_content_to_title(html: str) -> str:
title = '' title = ''
if '<p>' in html: if '<p>' in html:
@ -267,8 +274,7 @@ def microblog_content_to_title(html: str) -> str:
if title and title.strip() != '' and len(title.strip()) >= 5: if title and title.strip() != '' and len(title.strip()) >= 5:
break break
else: else:
soup = BeautifulSoup(html, 'html.parser') title = html_to_text(html)
title = soup.get_text()
period_index = title.find('.') period_index = title.find('.')
question_index = title.find('?') question_index = title.find('?')

View file

@ -0,0 +1,34 @@
"""comment length
Revision ID: e76f2067e689
Revises: 05e3a7023a1e
Create Date: 2024-05-21 21:58:22.133194
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'e76f2067e689'
down_revision = '05e3a7023a1e'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('user', schema=None) as batch_op:
batch_op.add_column(sa.Column('average_comment_length', sa.Integer(), nullable=True))
batch_op.add_column(sa.Column('comment_length_warning', sa.Integer(), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('user', schema=None) as batch_op:
batch_op.drop_column('comment_length_warning')
batch_op.drop_column('average_comment_length')
# ### end Alembic commands ###