diff --git a/app/community/routes.py b/app/community/routes.py index dc3c7e45..e9e3b3f9 100644 --- a/app/community/routes.py +++ b/app/community/routes.py @@ -101,7 +101,7 @@ def show_community(community: Community): abort(404) page = request.args.get('page', 1, type=int) - sort = request.args.get('sort', '') + sort = request.args.get('sort', '' if current_user.is_anonymous else current_user.default_sort) # If nothing has changed since their last visit, return HTTP 304 current_etag = f"{community.id}{sort}_{hash(community.last_active)}" @@ -133,6 +133,8 @@ def show_community(community: Community): 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)) posts = posts.paginate(page=page, per_page=100, error_out=False) description = shorten_string(community.description, 150) if community.description else None @@ -151,7 +153,7 @@ def show_community(community: Community): next_url=next_url, prev_url=prev_url, low_bandwidth=request.cookies.get('low_bandwidth', '0') == '1', rss_feed=f"https://{current_app.config['SERVER_NAME']}/community/{community.link()}/feed", rss_feed_name=f"{community.title} posts on PieFed", content_filters=content_filters, moderating_communities=moderating_communities(current_user.get_id()), - joined_communities=joined_communities(current_user.get_id())) + joined_communities=joined_communities(current_user.get_id()), sort=sort) # RSS feed of the community diff --git a/app/main/routes.py b/app/main/routes.py index b8b8e630..4d994d69 100644 --- a/app/main/routes.py +++ b/app/main/routes.py @@ -25,7 +25,7 @@ import pytesseract @bp.route('/', methods=['HEAD', 'GET', 'POST']) @bp.route('/home', methods=['GET', 'POST']) @bp.route('/home/', methods=['GET', 'POST']) -def index(sort='hot'): +def index(sort=None): if 'application/ld+json' in request.headers.get('Accept', '') or 'application/activity+json' in request.headers.get( 'Accept', ''): return activitypub_application() @@ -35,21 +35,24 @@ def index(sort='hot'): @bp.route('/popular', methods=['GET']) @bp.route('/popular/', methods=['GET']) -def popular(sort='hot'): +def popular(sort=None): return home_page('popular', sort) @bp.route('/all', methods=['GET']) @bp.route('/all/', methods=['GET']) -def all_posts(sort='hot'): +def all_posts(sort=None): return home_page('all', sort) -def home_page(type, sort='hot'): +def home_page(type, sort): verification_warning() + if sort is None: + sort = current_user.default_sort if current_user.is_authenticated else 'hot' + # If nothing has changed since their last visit, return HTTP 304 - current_etag = f"{type}_{hash(str(g.site.last_active))}" + current_etag = f"{type}_{sort}_{hash(str(g.site.last_active))}" if current_user.is_anonymous and request_etag_matches(current_etag): return return_304(current_etag) @@ -92,6 +95,8 @@ def home_page(type, sort='hot'): posts = posts.filter(Post.posted_at > utcnow() - timedelta(days=1)).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)) # Pagination posts = posts.paginate(page=page, per_page=100, error_out=False) @@ -111,7 +116,7 @@ def home_page(type, sort='hot'): POST_TYPE_IMAGE=POST_TYPE_IMAGE, POST_TYPE_LINK=POST_TYPE_LINK, low_bandwidth=request.cookies.get('low_bandwidth', '0') == '1', SUBSCRIPTION_PENDING=SUBSCRIPTION_PENDING, SUBSCRIPTION_MEMBER=SUBSCRIPTION_MEMBER, - etag=f"{type}_{hash(str(g.site.last_active))}", next_url=next_url, prev_url=prev_url, + etag=f"{type}_{sort}_{hash(str(g.site.last_active))}", next_url=next_url, prev_url=prev_url, rss_feed=f"https://{current_app.config['SERVER_NAME']}/feed", rss_feed_name=f"Posts on " + g.site.name, title=f"{g.site.name} - {g.site.description}", diff --git a/app/models.py b/app/models.py index 87eccb51..4e1ffb93 100644 --- a/app/models.py +++ b/app/models.py @@ -343,6 +343,7 @@ class User(UserMixin, db.Model): ip_address = db.Column(db.String(50)) instance_id = db.Column(db.Integer, db.ForeignKey('instance.id'), index=True) reports = db.Column(db.Integer, default=0) # how many times this user has been reported. + default_sort = db.Column(db.String(25), default='hot') 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") diff --git a/app/templates/_home_nav.html b/app/templates/_home_nav.html index e484d181..14dac914 100644 --- a/app/templates/_home_nav.html +++ b/app/templates/_home_nav.html @@ -8,4 +8,7 @@ {{ _('New') }} + + {{ _('Active') }} + \ No newline at end of file diff --git a/app/templates/community/_community_nav.html b/app/templates/community/_community_nav.html index 2a82c9ef..291dc313 100644 --- a/app/templates/community/_community_nav.html +++ b/app/templates/community/_community_nav.html @@ -2,13 +2,16 @@ {{ _('Create post') }} \ No newline at end of file diff --git a/app/templates/user/edit_settings.html b/app/templates/user/edit_settings.html index 9275a135..369fdc0f 100644 --- a/app/templates/user/edit_settings.html +++ b/app/templates/user/edit_settings.html @@ -20,6 +20,7 @@ {{ render_field(form.nsfl) }} {{ render_field(form.searchable) }} {{ render_field(form.indexable) }} + {{ render_field(form.default_sort) }} {{ render_field(form.import_file) }} {{ render_field(form.submit) }}   {{ _('Manage content filters') }} diff --git a/app/user/forms.py b/app/user/forms.py index a740d2d8..147ff8d1 100644 --- a/app/user/forms.py +++ b/app/user/forms.py @@ -2,7 +2,7 @@ from flask import session from flask_login import current_user from flask_wtf import FlaskForm from wtforms import StringField, SubmitField, PasswordField, BooleanField, EmailField, TextAreaField, FileField, \ - RadioField, DateField + RadioField, DateField, SelectField from wtforms.validators import ValidationError, DataRequired, Email, EqualTo, Length, Optional from flask_babel import _, lazy_gettext as _l @@ -35,6 +35,12 @@ class SettingsForm(FlaskForm): indexable = BooleanField(_l('Allow search engines to index this profile')) manually_approves_followers = BooleanField(_l('Manually approve followers')) import_file = FileField(_('Import community subscriptions and user blocks from Lemmy')) + sorts = [('hot', _l('Hot')), + ('top', _l('Top')), + ('new', _l('New')), + ('active', _l('Active')), + ] + default_sort = SelectField(_l('By default, sort posts by'), choices=sorts, validators=[DataRequired()], coerce=str) submit = SubmitField(_l('Save settings')) diff --git a/app/user/routes.py b/app/user/routes.py index 1507b4d5..b62f558b 100644 --- a/app/user/routes.py +++ b/app/user/routes.py @@ -158,6 +158,7 @@ def change_settings(): current_user.show_nsfl = form.nsfl.data current_user.searchable = form.searchable.data current_user.indexable = form.indexable.data + current_user.default_sort = form.default_sort.data import_file = request.files['import_file'] if import_file and import_file.filename != '': file_ext = os.path.splitext(import_file.filename)[1] @@ -187,6 +188,7 @@ def change_settings(): form.nsfl.data = current_user.show_nsfl form.searchable.data = current_user.searchable form.indexable.data = current_user.indexable + form.default_sort.data = current_user.default_sort return render_template('user/edit_settings.html', title=_('Edit profile'), form=form, user=current_user, moderating_communities=moderating_communities(current_user.get_id()), diff --git a/migrations/versions/b86c49cbd9a0_default_sort.py b/migrations/versions/b86c49cbd9a0_default_sort.py new file mode 100644 index 00000000..c1f3da8a --- /dev/null +++ b/migrations/versions/b86c49cbd9a0_default_sort.py @@ -0,0 +1,32 @@ +"""default sort + +Revision ID: b86c49cbd9a0 +Revises: 8885aafd5291 +Create Date: 2024-01-15 17:37:17.886232 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'b86c49cbd9a0' +down_revision = '8885aafd5291' +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('default_sort', sa.String(length=25), 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('default_sort') + + # ### end Alembic commands ###