diff --git a/files/classes/user.py b/files/classes/user.py index 4efbf44ee..b8d256564 100644 --- a/files/classes/user.py +++ b/files/classes/user.py @@ -110,6 +110,7 @@ class User(Base): original_username = deferred(Column(String)) referred_by = Column(Integer, ForeignKey("users.id")) subs_created = Column(Integer, default=0, nullable=False) + volunteer_last_started_utc = Column(DateTime, nullable=True) Index( 'users_original_username_trgm_idx', diff --git a/files/routes/volunteer.py b/files/routes/volunteer.py index 3ecd35199..c3ff3e452 100644 --- a/files/routes/volunteer.py +++ b/files/routes/volunteer.py @@ -1,16 +1,46 @@ +from datetime import datetime, timedelta from files.__main__ import app from files.classes.user import User import files.helpers.jinja2 from files.helpers.wrappers import auth_required -from flask import render_template +from flask import render_template, g +import sqlalchemy +from typing import Optional + +from files.routes.volunteer_common import VolunteerDuty +import files.routes.volunteer_janitor + +@files.helpers.jinja2.template_function +def volunteer_available_for(u: Optional[User]) -> bool: + return volunteer_get_duty(u) is not None + +def volunteer_get_duty(u: Optional[User]) -> Optional[VolunteerDuty]: + if u is None: + return None + + # check to make sure it's at least 20h since the last volunteer + if (u.volunteer_last_started_utc is not None) and (datetime.now() - u.volunteer_last_started_utc) < timedelta(hours = 20): + return None + + # TODO: clever code that figures out the most important duty available + janitor = files.routes.volunteer_janitor.get_duty(u) + if janitor is not None: + return janitor + + # oh well + return None + @app.get("/volunteer") @auth_required def volunteer(v: User): - return render_template("volunteer.html", v=v) + duty = volunteer_get_duty(v) + if duty is not None: + duty.accept() + v.volunteer_last_started_utc = sqlalchemy.func.now() + g.db.add(v) + g.db.commit() -@files.helpers.jinja2.template_function -def volunteer_available_for(u: User) -> bool: - return True + return render_template("volunteer.html", v=v, duty=duty) diff --git a/files/routes/volunteer_common.py b/files/routes/volunteer_common.py new file mode 100644 index 000000000..5a0eeb675 --- /dev/null +++ b/files/routes/volunteer_common.py @@ -0,0 +1,12 @@ + +from abc import ABC, abstractmethod + +class VolunteerDuty(ABC): + + @abstractmethod + def accept(self) -> None: + pass + + @abstractmethod + def embed_template(self) -> str: + return "" diff --git a/files/routes/volunteer_janitor.py b/files/routes/volunteer_janitor.py new file mode 100644 index 000000000..c7fae62ec --- /dev/null +++ b/files/routes/volunteer_janitor.py @@ -0,0 +1,58 @@ + +from files.classes.comment import Comment +from files.classes.flags import CommentFlag +from files.classes.user import User +from files.routes.volunteer_common import VolunteerDuty +from flask import g +import pprint +import random + +class VolunteerDutyJanitor(VolunteerDuty): + + def __init__(self, choices): + self.choices = choices + + def accept(self) -> None: + pprint.pprint(self.choices) + pass + + def embed_template(self) -> str: + return "volunteer_janitor.html" + +def get_duty(u: User) -> VolunteerDutyJanitor: + + # these could probably be combined into one query somehow + + # find reported comments not made by the current user + reported_comments = g.db.query(Comment) \ + .where(Comment.filter_state == 'reported') \ + .where(Comment.author_id != u.id) \ + .with_entities(Comment.id) + + reported_ids = [reported.id for reported in reported_comments] + + # find distinguished children of those reported comments + distinguished_children = g.db.query(Comment) \ + .where(Comment.parent_comment_id.in_(reported_ids)) \ + .where(Comment.distinguish_level > 0) \ + .with_entities(Comment.parent_comment_id) + + distinguished_children_ids = [child.parent_comment_id for child in distinguished_children] + + # filter + # we're doing this because we don't want to give people hints as to the "right" result + # once a modhat hits, that's it, doesn't show up in the volunteer system anymore + clean_reported = set(reported_ids) - set(distinguished_children_ids) + + # also, let's make sure it has a report that isn't made by this user + nonuser_reports = g.db.query(CommentFlag) \ + .where(CommentFlag.comment_id.in_(clean_reported)) \ + .where(CommentFlag.user_id != u.id) \ + .with_entities(CommentFlag.comment_id) + + final_reported = [report.comment_id for report in nonuser_reports] + + if len(final_reported) <= 0: + return None + + return VolunteerDutyJanitor(random.sample(final_reported, k = min(3, len(final_reported)))) diff --git a/files/templates/volunteer.html b/files/templates/volunteer.html index f18251b69..3ac9b19ab 100644 --- a/files/templates/volunteer.html +++ b/files/templates/volunteer.html @@ -5,7 +5,18 @@ {% block content %}
-hello! welcome to the volunteering + hello! welcome to the volunteering
+{% if duty == None %} +
+ there is no volunteering to do, but thanks +
+{% else %} +
+ {% from duty.embed_template() import display %} + {{ display(duty) }} +
+{% endif %} + {% endblock %} \ No newline at end of file diff --git a/files/templates/volunteer_janitor.html b/files/templates/volunteer_janitor.html new file mode 100644 index 000000000..1c38a91cd --- /dev/null +++ b/files/templates/volunteer_janitor.html @@ -0,0 +1,3 @@ +{% macro display(duty) %} +janny +{% endmacro %} diff --git a/migrations/versions/2022_11_14_11_24_55_d7a4a6723411_add_per_user_field_for_the_last_usage_.py b/migrations/versions/2022_11_14_11_24_55_d7a4a6723411_add_per_user_field_for_the_last_usage_.py new file mode 100644 index 000000000..3d33ae891 --- /dev/null +++ b/migrations/versions/2022_11_14_11_24_55_d7a4a6723411_add_per_user_field_for_the_last_usage_.py @@ -0,0 +1,28 @@ +"""Add per-user field for the last usage of the Volunteer page + +Revision ID: d7a4a6723411 +Revises: b23ec080ecb7 +Create Date: 2022-11-14 11:24:55.304258+00:00 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'd7a4a6723411' +down_revision = 'b23ec080ecb7' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('users', sa.Column('volunteer_last_started_utc', sa.DateTime(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('users', 'volunteer_last_started_utc') + # ### end Alembic commands ###