Volunteer Janitor: Initial duty acquisition.

This commit is contained in:
Ben Rog-Wilhelm 2022-11-19 01:32:46 -06:00 committed by Ben Rog-Wilhelm
parent e43db0535d
commit 03b323c7a1
7 changed files with 149 additions and 6 deletions

View file

@ -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',

View file

@ -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)

View file

@ -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 ""

View file

@ -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))))

View file

@ -5,7 +5,18 @@
{% block content %}
<div>
hello! welcome to the volunteering
hello! welcome to the volunteering
</div>
{% if duty == None %}
<div>
there is no volunteering to do, but thanks
</div>
{% else %}
<div>
{% from duty.embed_template() import display %}
{{ display(duty) }}
</div>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,3 @@
{% macro display(duty) %}
janny
{% endmacro %}

View file

@ -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 ###