Orders - Require alt text setting

This commit is contained in:
Johnny Gear 2026-03-30 16:18:30 -05:00
parent 87ddc4b998
commit ff7f59e8b0
8 changed files with 84 additions and 4 deletions

View file

@ -36,6 +36,7 @@ class User(BaseModel):
mastodon_attn_list = TextField(null=True) mastodon_attn_list = TextField(null=True)
mastodon_post_public = BooleanField(null=True, default=False) mastodon_post_public = BooleanField(null=True, default=False)
verify_mastodon_alt_text = BooleanField(null=False, default=False)
verify_mastodon_favorite = BooleanField(null=False, default=False) verify_mastodon_favorite = BooleanField(null=False, default=False)
verify_delay = IntegerField(null=True) verify_delay = IntegerField(null=True)

View file

@ -0,0 +1,49 @@
"""Peewee migrations -- 028_add_verify_mastodon_alt_text.py.
Some examples (model - class or model name)::
> Model = migrator.orm['table_name'] # Return model in current state by name
> Model = migrator.ModelClass # Return model in current state by name
> migrator.sql(sql) # Run custom SQL
> migrator.run(func, *args, **kwargs) # Run python function with the given args
> migrator.create_model(Model) # Create a model (could be used as decorator)
> migrator.remove_model(model, cascade=True) # Remove a model
> migrator.add_fields(model, **fields) # Add fields to a model
> migrator.change_fields(model, **fields) # Change fields
> migrator.remove_fields(model, *field_names, cascade=True)
> migrator.rename_field(model, old_field_name, new_field_name)
> migrator.rename_table(model, new_table_name)
> migrator.add_index(model, *col_names, unique=False)
> migrator.add_not_null(model, *field_names)
> migrator.add_default(model, field_name, default)
> migrator.add_constraint(model, name, sql)
> migrator.drop_index(model, *col_names)
> migrator.drop_not_null(model, *field_names)
> migrator.drop_constraints(model, *constraints)
"""
from contextlib import suppress
import peewee as pw
from peewee_migrate import Migrator
with suppress(ImportError):
import playhouse.postgres_ext as pw_pext
def migrate(migrator: Migrator, database: pw.Database, *, fake=False):
"""Write your migrations here."""
migrator.add_fields(
'user',
verify_mastodon_alt_text=pw.BooleanField(default=False))
def rollback(migrator: Migrator, database: pw.Database, *, fake=False):
"""Write your rollback migrations here."""
migrator.remove_fields('user', 'verify_mastodon_alt_text')

View file

@ -226,6 +226,7 @@ async def order_check(order_status_id):
confirmed_at = None confirmed_at = None
had_replies = False had_replies = False
had_reply_on_time = False had_reply_on_time = False
had_alt_text = False
had_media_attachment = False had_media_attachment = False
had_favorites = False had_favorites = False
for d in context['descendants']: for d in context['descendants']:
@ -234,6 +235,10 @@ async def order_check(order_status_id):
d['account']['acct'] == order_status.user.mastodon_account() d['account']['acct'] == order_status.user.mastodon_account()
): ):
had_replies = True had_replies = True
had_reply_on_time = False
had_alt_text = False
had_media_attachment = False
had_favorites = False
if (datetime.datetime.fromisoformat(d['created_at']) < if (datetime.datetime.fromisoformat(d['created_at']) <
datetime.datetime.fromisoformat(order_status.due_at)): datetime.datetime.fromisoformat(order_status.due_at)):
@ -246,6 +251,14 @@ async def order_check(order_status_id):
else: else:
continue continue
if user.verify_mastodon_alt_text:
if all([(
'description' in a and a['description'] is not None
) for a in d['media_attachments']]):
had_alt_text = True
else:
continue
if user.verify_mastodon_favorite: if user.verify_mastodon_favorite:
if await status_has_favorites(m, d['id'], order_status.user): if await status_has_favorites(m, d['id'], order_status.user):
had_favorites = True had_favorites = True
@ -279,7 +292,9 @@ async def order_check(order_status_id):
reason = "Reply was after due date" reason = "Reply was after due date"
elif had_media_attachment is False: elif had_media_attachment is False:
reason = "No replies had a media attachment" reason = "No replies had a media attachment"
elif had_favorites is False: elif user.verify_mastodon_alt_text and had_alt_text is False:
reason = "Not all media attachments had alt text"
elif user.verify_mastodon_favorite and had_favorites is False:
reason = "No replies had a favorite from a dom or tagged account" reason = "No replies had a favorite from a dom or tagged account"
logger.info('Time to issue a punishment for %s' % order_status.id) logger.info('Time to issue a punishment for %s' % order_status.id)

View file

@ -32,6 +32,7 @@ def me():
if not has_doms: if not has_doms:
result["verify_mastodon_alt_text"] = user.verify_mastodon_alt_text
result["verify_mastodon_favorite"] = user.verify_mastodon_favorite result["verify_mastodon_favorite"] = user.verify_mastodon_favorite
result["verify_delay"] = user.verify_delay result["verify_delay"] = user.verify_delay
@ -168,6 +169,7 @@ def sub(username, sub):
if request.method == "POST": if request.method == "POST":
sub.verify_mastodon_favorite = bool(request.json['verify_mastodon_favorite']) sub.verify_mastodon_favorite = bool(request.json['verify_mastodon_favorite'])
sub.verify_mastodon_alt_text = bool(request.json['verify_mastodon_alt_text'])
if request.json['verify_delay'] is not None: if request.json['verify_delay'] is not None:
sub.verify_delay = int(request.json["verify_delay"]) sub.verify_delay = int(request.json["verify_delay"])
@ -179,6 +181,7 @@ def sub(username, sub):
"username": sub.telegram_username, "username": sub.telegram_username,
"mastodon_server": sub.mastodon_server.name if sub.mastodon_server is not None else None, "mastodon_server": sub.mastodon_server.name if sub.mastodon_server is not None else None,
"mastodon_username": sub.mastodon_username, "mastodon_username": sub.mastodon_username,
"verify_mastodon_alt_text": sub.verify_mastodon_alt_text,
"verify_mastodon_favorite": sub.verify_mastodon_favorite, "verify_mastodon_favorite": sub.verify_mastodon_favorite,
"verify_delay": sub.verify_delay "verify_delay": sub.verify_delay
}) })

View file

@ -68,6 +68,7 @@ export const Profile: React.FC = () => {
has_doms, has_doms,
mastodon_attn_list, mastodon_attn_list,
mastodon_post_public, mastodon_post_public,
verify_mastodon_alt_text,
verify_mastodon_favorite, verify_mastodon_favorite,
verify_delay, verify_delay,
} = useLoaderData<UserProfile>(); } = useLoaderData<UserProfile>();
@ -162,6 +163,7 @@ export const Profile: React.FC = () => {
{!has_doms ? ( {!has_doms ? (
<ProfileVerification <ProfileVerification
username={username} username={username}
verify_mastodon_alt_text={verify_mastodon_alt_text}
verify_mastodon_favorite={verify_mastodon_favorite} verify_mastodon_favorite={verify_mastodon_favorite}
verify_delay={verify_delay} verify_delay={verify_delay}
/> />

View file

@ -13,16 +13,17 @@ import React from "react";
type ProfileVerificationProps = Pick< type ProfileVerificationProps = Pick<
UserProfile, UserProfile,
"verify_mastodon_favorite" | "verify_delay" "verify_mastodon_alt_text" | "verify_mastodon_favorite" | "verify_delay"
> & { username: string }; > & { username: string };
type OrderVerificationForm = Pick< type OrderVerificationForm = Pick<
UserProfile, UserProfile,
"verify_mastodon_favorite" | "verify_delay" "verify_mastodon_alt_text" | "verify_mastodon_favorite" | "verify_delay"
>; >;
export const ProfileVerification: React.FC<ProfileVerificationProps> = ({ export const ProfileVerification: React.FC<ProfileVerificationProps> = ({
username, username,
verify_mastodon_alt_text,
verify_mastodon_favorite, verify_mastodon_favorite,
verify_delay, verify_delay,
}) => { }) => {
@ -30,12 +31,12 @@ export const ProfileVerification: React.FC<ProfileVerificationProps> = ({
const form = useForm<OrderVerificationForm>({ const form = useForm<OrderVerificationForm>({
mode: "uncontrolled", mode: "uncontrolled",
initialValues: { initialValues: {
verify_mastodon_alt_text,
verify_mastodon_favorite, verify_mastodon_favorite,
verify_delay, verify_delay,
}, },
validate: { validate: {
verify_delay: (value: number, values: OrderVerificationForm) => { verify_delay: (value: number, values: OrderVerificationForm) => {
console.log("oh boy", values.verify_mastodon_favorite, value);
return !values.verify_mastodon_favorite || value return !values.verify_mastodon_favorite || value
? null ? null
: "You must set a verification delay"; : "You must set a verification delay";
@ -79,6 +80,13 @@ export const ProfileVerification: React.FC<ProfileVerificationProps> = ({
<Title order={4} mb="md"> <Title order={4} mb="md">
Order Verification Order Verification
</Title> </Title>
<Checkbox
{...form.getInputProps("verify_mastodon_alt_text", {
type: "checkbox",
})}
label="Media on posts must have alt text"
mb="md"
/>
<Checkbox <Checkbox
{...form.getInputProps("verify_mastodon_favorite", { {...form.getInputProps("verify_mastodon_favorite", {
type: "checkbox", type: "checkbox",

View file

@ -35,6 +35,7 @@ export const SubOrderSets: React.FC = () => {
</Title> </Title>
<ProfileVerification <ProfileVerification
username={sub_username} username={sub_username}
verify_mastodon_alt_text={profile.verify_mastodon_alt_text}
verify_mastodon_favorite={profile.verify_mastodon_favorite} verify_mastodon_favorite={profile.verify_mastodon_favorite}
verify_delay={profile.verify_delay} verify_delay={profile.verify_delay}
/> />

View file

@ -6,6 +6,7 @@ type UserProfile = {
mastodon_attn_list?: string; mastodon_attn_list?: string;
mastodon_post_public: boolean; mastodon_post_public: boolean;
has_doms: boolean; has_doms: boolean;
verify_mastodon_alt_text?: boolean;
verify_mastodon_favorite?: boolean; verify_mastodon_favorite?: boolean;
verify_delay?: number; verify_delay?: number;
} }