UI for advanced sub permissions

This commit is contained in:
John Groszko 2026-04-23 14:54:47 -05:00
parent 40486f81fd
commit 34e8d0eae3
4 changed files with 175 additions and 11 deletions

View file

@ -6,7 +6,7 @@ from flask import Blueprint, jsonify, abort, request
from flask_login import login_required, current_user
from db.constants import TIMELINE_ORDERS_POOL_CREATED, TIMELINE_ORDERS_POOL_DELETED, TIMELINE_ORDERS_POOL_UPDATED
from db.models import database, OrdersPool, Order, OrderAddOn, MastodonServer
from db.queries import timeline_event_put, timeline_event_recent, user_can_orders_pools_details, user_can_orders_pools_edit, user_can_orders_pools_view, user_get, domsubusers_list, orders_pool_list, orders_pool, mastodon_server_get, mastodon_server_put, user_has_doms, user_mastodon_server_set, user_preferences_set
from db.queries import timeline_event_put, timeline_event_recent, user_can_orders_pools_details, user_can_orders_pools_edit, user_can_orders_pools_view, user_doms, user_get, domsubusers_list, orders_pool_list, orders_pool, mastodon_server_get, mastodon_server_put, user_has_doms, user_mastodon_server_set, user_preferences_set
from settings import MASTODON_OAUTH_CLIENT_NAME, MASTODON_OAUTH_REDIRECT_URI, MASTODON_OAUTH_SCOPES, MASTODON_OAUTH_CLIENT_WEBSITE
from util import time_sqlite
@ -164,15 +164,27 @@ def authorized_sub(func):
@authorized_sub
def sub(username, sub):
if request.method == "POST":
if user_has_doms(sub) and sub.id == current_user.db_user.id:
if (user_has_doms(sub) and sub.id == current_user.db_user.id and
('permission_orders_pools_view' in request.json or
'permission_orders_pools_details' in request.json or
'permission_orders_pools_edit' in request.json)):
abort(403)
return
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 'verify_mastodon_favorite' in request.json:
sub.verify_mastodon_favorite = bool(request.json['verify_mastodon_favorite'])
if 'verify_mastodon_alt_text' in request.json:
sub.verify_mastodon_alt_text = bool(request.json['verify_mastodon_alt_text'])
if 'verify_delay' in request.json and request.json['verify_delay'] is not None:
sub.verify_delay = int(request.json["verify_delay"])
if 'permission_orders_pools_view' in request.json:
sub.permission_orders_pools_view = bool(request.json['permission_orders_pools_view'])
if 'permission_orders_pools_details' in request.json:
sub.permission_orders_pools_details = bool(request.json['permission_orders_pools_details'])
if 'permission_orders_pools_edit' in request.json:
sub.permission_orders_pools_edit = bool(request.json['permission_orders_pools_edit'])
sub.save()
return ('', 204)
@ -183,7 +195,11 @@ def sub(username, sub):
"mastodon_username": sub.mastodon_username,
"verify_mastodon_alt_text": sub.verify_mastodon_alt_text,
"verify_mastodon_favorite": sub.verify_mastodon_favorite,
"verify_delay": sub.verify_delay
"verify_delay": sub.verify_delay,
"can_edit_permissions": current_user.db_user in user_doms(sub.id),
"permission_orders_pools_view": sub.permission_orders_pools_view,
"permission_orders_pools_details": sub.permission_orders_pools_details,
"permission_orders_pools_edit": sub.permission_orders_pools_edit
})
@api.route('/orders/')

View file

@ -0,0 +1,129 @@
import React from "react";
import { Button, Checkbox, Paper, Title } from "@mantine/core";
import { useForm } from "@mantine/form";
import { notifications } from "@mantine/notifications";
import { fetchHeaders } from "./fetch";
type ProfilePermissionsProps = Pick<
UserProfile,
| "permission_orders_pools_view"
| "permission_orders_pools_details"
| "permission_orders_pools_edit"
> & { username: string };
type ProfilePermissionsForm = Pick<
UserProfile,
| "permission_orders_pools_view"
| "permission_orders_pools_details"
| "permission_orders_pools_edit"
>;
export const ProfilePermissions: React.FC<ProfilePermissionsProps> = ({
username,
permission_orders_pools_view,
permission_orders_pools_details,
permission_orders_pools_edit,
}) => {
const [loading, setLoading] = React.useState(false);
const [detailsDisabled, setDetailsDisabled] = React.useState(
!permission_orders_pools_view,
);
const [editDisabled, setEditDisabled] = React.useState(
!permission_orders_pools_details,
);
const form = useForm<ProfilePermissionsForm>({
mode: "uncontrolled",
initialValues: {
permission_orders_pools_view,
permission_orders_pools_details,
permission_orders_pools_edit,
},
});
form.watch("permission_orders_pools_view", ({ value }) => {
if (!value) {
form.setFieldValue("permission_orders_pools_details", false);
setDetailsDisabled(true);
} else {
setDetailsDisabled(false);
}
});
form.watch("permission_orders_pools_details", ({ value }) => {
if (!value) {
form.setFieldValue("permission_orders_pools_edit", false);
setEditDisabled(true);
} else {
setEditDisabled(false);
}
});
const handleSubmit = React.useCallback(
form.onSubmit((values) => {
setLoading(true);
fetch(`/api/subs/${username}`, {
method: "POST",
headers: fetchHeaders(),
body: JSON.stringify(values),
})
.then((response) => {
if (response.ok) {
notifications.show({
title: "Success",
message: "Permissions have been saved",
color: "green",
});
} else {
notifications.show({
title: "Error",
message: "There was a problem saving permissions",
color: "red",
});
}
})
.finally(() => {
setLoading(false);
});
}),
[],
);
return (
<Paper>
<form onSubmit={handleSubmit}>
<Title order={4} mb="md">
Permissions
</Title>
<Checkbox
{...form.getInputProps("permission_orders_pools_view", {
type: "checkbox",
})}
key={form.key("permission_orders_pools_view")}
label="Sub can view orders sets"
mb="md"
/>
<Checkbox
{...form.getInputProps("permission_orders_pools_details", {
type: "checkbox",
})}
key={form.key("permission_orders_pools_details")}
disabled={detailsDisabled}
label="Sub can view orders sets details"
mb="md"
/>
<Checkbox
{...form.getInputProps("permission_orders_pools_edit", {
type: "checkbox",
})}
key={form.key("permission_orders_pools_edit")}
disabled={editDisabled}
label="Sub can edit orders sets"
mb="md"
/>
<Button type="submit" loading={loading} mt="md">
Save
</Button>
</form>
</Paper>
);
};

View file

@ -3,6 +3,7 @@ import { Params, useLoaderData, useParams, Link } from "react-router";
import { OrderSetProps, OrderSets, OrderSetsResponse } from "./OrderSets";
import { ProfileVerification } from "./ProfileVerification";
import { Anchor, Title } from "@mantine/core";
import { ProfilePermissions } from "./ProfilePermissions";
export const userOrderSetsLoader = async ({
params: { username },
@ -16,11 +17,11 @@ export const UserOrderSets: React.FC = () => {
const [profile, setProfile] = React.useState<UserProfile | null>(null);
React.useEffect(() => {
// fetch(`/api/subs/${sub_username}`).then(async (response) => {
// if (response.ok) {
// setProfile(await response.json());
// }
// });
fetch(`/api/subs/${sub_username}`).then(async (response) => {
if (response.ok) {
setProfile(await response.json());
}
});
}, [sub_username]);
return (
@ -46,6 +47,20 @@ export const UserOrderSets: React.FC = () => {
verify_mastodon_favorite={profile.verify_mastodon_favorite}
verify_delay={profile.verify_delay}
/>
{profile.can_edit_permissions ? (
<ProfilePermissions
username={sub_username}
permission_orders_pools_view={
profile.permission_orders_pools_view
}
permission_orders_pools_details={
profile.permission_orders_pools_details
}
permission_orders_pools_edit={
profile.permission_orders_pools_edit
}
/>
) : null}
</>
) : null}
</>

View file

@ -9,6 +9,10 @@ type UserProfile = {
verify_mastodon_alt_text?: boolean;
verify_mastodon_favorite?: boolean;
verify_delay?: number;
can_edit_permissions?: boolean;
permission_orders_pools_view?: boolean;
permission_orders_pools_details?: boolean;
permission_orders_pools_edit?: boolean;
}
type OrderSetOrderAddOn = {