Add advanced sub permissions
This commit is contained in:
parent
05d5093e23
commit
40486f81fd
9 changed files with 405 additions and 172 deletions
|
|
@ -40,6 +40,10 @@ class User(BaseModel):
|
||||||
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)
|
||||||
|
|
||||||
|
permission_orders_pools_view = BooleanField(null=False, default=True)
|
||||||
|
permission_orders_pools_details = BooleanField(null=False, default=True)
|
||||||
|
permission_orders_pools_edit = BooleanField(null=False, default=True)
|
||||||
|
|
||||||
def mastodon_account(self):
|
def mastodon_account(self):
|
||||||
if self.mastodon_server is None or self.mastodon_username is None:
|
if self.mastodon_server is None or self.mastodon_username is None:
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,42 @@ def user_preferences_set(id, mastodon_post_public, mastodon_attn_list):
|
||||||
def user_has_doms(id):
|
def user_has_doms(id):
|
||||||
return DomSubUsers.select().where(DomSubUsers.sub_id == id).count() > 0
|
return DomSubUsers.select().where(DomSubUsers.sub_id == id).count() > 0
|
||||||
|
|
||||||
|
def user_doms(id):
|
||||||
|
return [d.dom for d in DomSubUsers.select(DomSubUsers.dom).where(DomSubUsers.sub_id == id)]
|
||||||
|
|
||||||
|
def user_can_orders_pools_view(user, sub):
|
||||||
|
doms = user_doms(sub.id)
|
||||||
|
|
||||||
|
if len(doms) > 0:
|
||||||
|
if user == sub:
|
||||||
|
return user.permission_orders_pools_view
|
||||||
|
else:
|
||||||
|
return user in doms
|
||||||
|
else:
|
||||||
|
return user.id == sub.id
|
||||||
|
|
||||||
|
def user_can_orders_pools_details(user, sub):
|
||||||
|
doms = user_doms(sub.id)
|
||||||
|
|
||||||
|
if len(doms) > 0:
|
||||||
|
if user == sub:
|
||||||
|
return user.permission_orders_pools_details
|
||||||
|
else:
|
||||||
|
return user in doms
|
||||||
|
else:
|
||||||
|
return user.id == sub.id
|
||||||
|
|
||||||
|
def user_can_orders_pools_edit(user, sub):
|
||||||
|
doms = user_doms(sub.id)
|
||||||
|
|
||||||
|
if len(doms) > 0:
|
||||||
|
if user == sub:
|
||||||
|
return user.permission_orders_pools_edit
|
||||||
|
else:
|
||||||
|
return user in doms
|
||||||
|
else:
|
||||||
|
return user.id == sub.id
|
||||||
|
|
||||||
def mastodon_server_get(name):
|
def mastodon_server_get(name):
|
||||||
return MastodonServer.get(name=name)
|
return MastodonServer.get(name=name)
|
||||||
|
|
||||||
|
|
|
||||||
51
migrations/029_add_sub_permissions.py
Normal file
51
migrations/029_add_sub_permissions.py
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
"""Peewee migrations -- 029_add_sub_permissions.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',
|
||||||
|
|
||||||
|
permission_orders_pools_view=pw.BooleanField(default=True),
|
||||||
|
permission_orders_pools_details=pw.BooleanField(default=True),
|
||||||
|
permission_orders_pools_edit=pw.BooleanField(default=True))
|
||||||
|
|
||||||
|
|
||||||
|
def rollback(migrator: Migrator, database: pw.Database, *, fake=False):
|
||||||
|
"""Write your rollback migrations here."""
|
||||||
|
|
||||||
|
migrator.remove_fields('user', 'permission_orders_pools_view', 'permission_orders_pools_details', 'permission_orders_pools_edit')
|
||||||
77
web/api.py
77
web/api.py
|
|
@ -6,7 +6,7 @@ from flask import Blueprint, jsonify, abort, request
|
||||||
from flask_login import login_required, current_user
|
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.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.models import database, OrdersPool, Order, OrderAddOn, MastodonServer
|
||||||
from db.queries import timeline_event_put, timeline_event_recent, 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_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 settings import MASTODON_OAUTH_CLIENT_NAME, MASTODON_OAUTH_REDIRECT_URI, MASTODON_OAUTH_SCOPES, MASTODON_OAUTH_CLIENT_WEBSITE
|
||||||
from util import time_sqlite
|
from util import time_sqlite
|
||||||
|
|
||||||
|
|
@ -163,11 +163,11 @@ def authorized_sub(func):
|
||||||
@login_required
|
@login_required
|
||||||
@authorized_sub
|
@authorized_sub
|
||||||
def sub(username, 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:
|
||||||
abort(403)
|
abort(403)
|
||||||
return
|
return
|
||||||
|
|
||||||
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'])
|
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:
|
||||||
|
|
@ -189,7 +189,17 @@ def sub(username, sub):
|
||||||
@api.route('/orders/')
|
@api.route('/orders/')
|
||||||
@login_required
|
@login_required
|
||||||
def my_order_sets():
|
def my_order_sets():
|
||||||
return jsonify([
|
user = current_user.db_user
|
||||||
|
result = {
|
||||||
|
'permissions': {
|
||||||
|
'can_view': user_can_orders_pools_view(user, user),
|
||||||
|
'can_details': user_can_orders_pools_details(user, user),
|
||||||
|
'can_edit': user_can_orders_pools_edit(user, user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result['permissions']['can_details']:
|
||||||
|
result['pools'] = [
|
||||||
{
|
{
|
||||||
'id': op.id,
|
'id': op.id,
|
||||||
'name': op.name,
|
'name': op.name,
|
||||||
|
|
@ -207,13 +217,39 @@ def my_order_sets():
|
||||||
}
|
}
|
||||||
for op
|
for op
|
||||||
in orders_pool_list(current_user.db_user)
|
in orders_pool_list(current_user.db_user)
|
||||||
])
|
]
|
||||||
|
elif result['permissions']['can_view']:
|
||||||
|
result['pools'] = [
|
||||||
|
{
|
||||||
|
'id': op.id,
|
||||||
|
'name': op.name,
|
||||||
|
'scheduled': op.scheduled,
|
||||||
|
'time': op.time,
|
||||||
|
'weekends': op.weekends,
|
||||||
|
'weekdays': op.weekdays,
|
||||||
|
'probability': op.probability,
|
||||||
|
'punishment_pool_name': op.punishment_pool.name if op.punishment_pool is not None else None,
|
||||||
|
}
|
||||||
|
for op
|
||||||
|
in orders_pool_list(current_user.db_user)
|
||||||
|
]
|
||||||
|
|
||||||
|
return jsonify(result)
|
||||||
|
|
||||||
@api.route('/orders/<username>/sets')
|
@api.route('/orders/<username>/sets')
|
||||||
@login_required
|
@login_required
|
||||||
@authorized_sub
|
@authorized_sub
|
||||||
def sub_order_sets(username, sub):
|
def sub_order_sets(username, sub):
|
||||||
return jsonify([
|
result = {
|
||||||
|
'permissions': {
|
||||||
|
'can_view': user_can_orders_pools_view(current_user.db_user, sub),
|
||||||
|
'can_details': user_can_orders_pools_details(current_user.db_user, sub),
|
||||||
|
'can_edit': user_can_orders_pools_edit(current_user.db_user, sub)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result['permissions']['can_details']:
|
||||||
|
result['pools'] = [
|
||||||
{
|
{
|
||||||
'id': op.id,
|
'id': op.id,
|
||||||
'name': op.name,
|
'name': op.name,
|
||||||
|
|
@ -231,12 +267,33 @@ def sub_order_sets(username, sub):
|
||||||
}
|
}
|
||||||
for op
|
for op
|
||||||
in orders_pool_list(sub.id)
|
in orders_pool_list(sub.id)
|
||||||
])
|
]
|
||||||
|
elif result['permissions']['can_view']:
|
||||||
|
result['pools'] = [
|
||||||
|
{
|
||||||
|
'id': op.id,
|
||||||
|
'name': op.name,
|
||||||
|
'scheduled': op.scheduled,
|
||||||
|
'time': op.time,
|
||||||
|
'weekends': op.weekends,
|
||||||
|
'weekdays': op.weekdays,
|
||||||
|
'probability': op.probability,
|
||||||
|
'punishment_pool_name': op.punishment_pool.name if op.punishment_pool is not None else None,
|
||||||
|
}
|
||||||
|
for op
|
||||||
|
in orders_pool_list(sub.id)
|
||||||
|
]
|
||||||
|
|
||||||
|
return jsonify(result)
|
||||||
|
|
||||||
@api.route('/orders/<username>/sets/', methods=['POST'])
|
@api.route('/orders/<username>/sets/', methods=['POST'])
|
||||||
@login_required
|
@login_required
|
||||||
@authorized_sub
|
@authorized_sub
|
||||||
def sub_order_set_create(username, sub):
|
def sub_order_set_create(username, sub):
|
||||||
|
if not user_can_orders_pools_edit(current_user.db_user, sub):
|
||||||
|
abort(403)
|
||||||
|
return
|
||||||
|
|
||||||
# Create new
|
# Create new
|
||||||
with database.atomic() as transaction:
|
with database.atomic() as transaction:
|
||||||
try:
|
try:
|
||||||
|
|
@ -287,6 +344,10 @@ def sub_order_set(username, set_id, sub):
|
||||||
op = orders_pool(sub.id, set_id)
|
op = orders_pool(sub.id, set_id)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
if not user_can_orders_pools_edit(current_user.db_user, sub):
|
||||||
|
abort(403)
|
||||||
|
return
|
||||||
|
|
||||||
def update_add_ons(order, add_ons):
|
def update_add_ons(order, add_ons):
|
||||||
for updated_add_on in add_ons:
|
for updated_add_on in add_ons:
|
||||||
if isinstance(updated_add_on['id'], int):
|
if isinstance(updated_add_on['id'], int):
|
||||||
|
|
@ -371,6 +432,10 @@ def sub_order_set(username, set_id, sub):
|
||||||
abort(500)
|
abort(500)
|
||||||
elif request.method == 'DELETE':
|
elif request.method == 'DELETE':
|
||||||
try:
|
try:
|
||||||
|
if not user_can_orders_pools_edit(current_user.db_user, sub):
|
||||||
|
abort(403)
|
||||||
|
return
|
||||||
|
|
||||||
op.delete_instance(recursive=True)
|
op.delete_instance(recursive=True)
|
||||||
|
|
||||||
timeline_event_put(
|
timeline_event_put(
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { Text, Title, Flex, Card, Image } from "@mantine/core";
|
||||||
import { useLoaderData } from "react-router";
|
import { useLoaderData } from "react-router";
|
||||||
import { IconPencil } from "@tabler/icons-react";
|
import { IconPencil } from "@tabler/icons-react";
|
||||||
import { NavigateButton } from "./NavigateButton";
|
import { NavigateButton } from "./NavigateButton";
|
||||||
import { OrderSetProps, OrderSets } from "./OrderSets";
|
import { OrderSets, OrderSetsResponse } from "./OrderSets";
|
||||||
import { useUserContext } from "./UserContext";
|
import { useUserContext } from "./UserContext";
|
||||||
import { TimelineList } from "./TimelineList";
|
import { TimelineList } from "./TimelineList";
|
||||||
|
|
||||||
|
|
@ -54,14 +54,20 @@ const SubsList: React.FC<SubsListProps> = ({ subs }) => (
|
||||||
export const Dashboard: React.FC = () => {
|
export const Dashboard: React.FC = () => {
|
||||||
const [orderSets, subs, timeline] =
|
const [orderSets, subs, timeline] =
|
||||||
useLoaderData<
|
useLoaderData<
|
||||||
[OrderSetProps["orderSets"], SubsListProps["subs"], TimelineEvent[]]
|
[OrderSetsResponse, SubsListProps["subs"], TimelineEvent[]]
|
||||||
>();
|
>();
|
||||||
const { username } = useUserContext();
|
const { username } = useUserContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{timeline.length > 0 ? <TimelineList timeline={timeline} /> : null}
|
{timeline.length > 0 ? <TimelineList timeline={timeline} /> : null}
|
||||||
<OrderSets orderSets={orderSets} username={username} />
|
{orderSets.permissions?.can_view && orderSets.pools.length > 0 ? (
|
||||||
|
<OrderSets
|
||||||
|
orderSets={orderSets.pools}
|
||||||
|
permissions={orderSets.permissions}
|
||||||
|
username={username}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
{subs.length > 0 ? <SubsList subs={subs} /> : null}
|
{subs.length > 0 ? <SubsList subs={subs} /> : null}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -83,9 +83,22 @@ export const OrderSet: React.FC = () => {
|
||||||
|
|
||||||
const [orderSets, setOrderSets] = React.useState([]);
|
const [orderSets, setOrderSets] = React.useState([]);
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
fetch(`/api/orders/${username}/sets`)
|
fetch(`/api/orders/${username}/sets`).then(async (response) => {
|
||||||
.then((response) => response.json())
|
if (response.ok) {
|
||||||
.then(setOrderSets);
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (!data.permissions?.can_edit) {
|
||||||
|
notifications.show({
|
||||||
|
title: "Error",
|
||||||
|
message: "Not authorized",
|
||||||
|
color: "red",
|
||||||
|
});
|
||||||
|
navigate(`/dashboard/`);
|
||||||
|
}
|
||||||
|
|
||||||
|
setOrderSets(data.pools);
|
||||||
|
}
|
||||||
|
});
|
||||||
}, [username]);
|
}, [username]);
|
||||||
|
|
||||||
const [showScheduling, setShowScheduling] = React.useState(
|
const [showScheduling, setShowScheduling] = React.useState(
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,28 @@ const COLORS_ROTATION = [
|
||||||
"gray.4",
|
"gray.4",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export interface OrderSetsResponse {
|
||||||
|
pools: (Pick<
|
||||||
|
OrderSet,
|
||||||
|
| "id"
|
||||||
|
| "name"
|
||||||
|
| "scheduled"
|
||||||
|
| "time"
|
||||||
|
| "weekends"
|
||||||
|
| "weekdays"
|
||||||
|
| "orders"
|
||||||
|
| "probability"
|
||||||
|
> & {
|
||||||
|
orders: Pick<OrderSetOrder, "id" | "name" | "weight">;
|
||||||
|
punishment_pool_name: string;
|
||||||
|
})[];
|
||||||
|
permissions: {
|
||||||
|
can_view: boolean;
|
||||||
|
can_details: boolean;
|
||||||
|
can_edit: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderSetProps {
|
export interface OrderSetProps {
|
||||||
orderSets: (Pick<
|
orderSets: (Pick<
|
||||||
OrderSet,
|
OrderSet,
|
||||||
|
|
@ -49,12 +71,14 @@ export interface OrderSetProps {
|
||||||
})[];
|
})[];
|
||||||
username: string;
|
username: string;
|
||||||
linkBack?: React.ReactNode;
|
linkBack?: React.ReactNode;
|
||||||
|
permissions?: OrderSetsResponse["permissions"];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const OrderSets: React.FC<OrderSetProps> = ({
|
export const OrderSets: React.FC<OrderSetProps> = ({
|
||||||
orderSets,
|
orderSets,
|
||||||
username,
|
username,
|
||||||
linkBack,
|
linkBack,
|
||||||
|
permissions,
|
||||||
}) => {
|
}) => {
|
||||||
const { username: current_user } = useUserContext();
|
const { username: current_user } = useUserContext();
|
||||||
const fetcher = useFetcher();
|
const fetcher = useFetcher();
|
||||||
|
|
@ -71,12 +95,13 @@ export const OrderSets: React.FC<OrderSetProps> = ({
|
||||||
const [isMastodonSet, setIsMastodonSet] = React.useState(true);
|
const [isMastodonSet, setIsMastodonSet] = React.useState(true);
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (username) {
|
if (username) {
|
||||||
fetch(`/api/subs/${username}`)
|
fetch(`/api/subs/${username}`).then(async (response) => {
|
||||||
.then((response) => response.json())
|
if (response.ok) {
|
||||||
.then((data) => {
|
const data = await response.json();
|
||||||
if (!data.mastodon_server || !data.mastodon_username) {
|
if (!data.mastodon_server || !data.mastodon_username) {
|
||||||
setIsMastodonSet(false);
|
setIsMastodonSet(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [username]);
|
}, [username]);
|
||||||
|
|
@ -84,12 +109,12 @@ export const OrderSets: React.FC<OrderSetProps> = ({
|
||||||
const [portalRef, setPortalRef] = React.useState<HTMLElement | null>();
|
const [portalRef, setPortalRef] = React.useState<HTMLElement | null>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Box my="lg">
|
||||||
<Box mb="lg">
|
<Box mb="lg">
|
||||||
<Title order={1}>Order Sets for {username}</Title>
|
<Title order={1}>Order Sets for {username}</Title>
|
||||||
{linkBack ? linkBack : null}
|
{linkBack ? linkBack : null}
|
||||||
</Box>
|
</Box>
|
||||||
{orderSets.length > 0 && isMastodonSet ? null : (
|
{isMastodonSet ? null : (
|
||||||
<Flex justify="center">
|
<Flex justify="center">
|
||||||
<Alert
|
<Alert
|
||||||
variant="light"
|
variant="light"
|
||||||
|
|
@ -119,6 +144,7 @@ export const OrderSets: React.FC<OrderSetProps> = ({
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{permissions?.can_view ? (
|
||||||
<Grid gutter="md">
|
<Grid gutter="md">
|
||||||
{orderSets
|
{orderSets
|
||||||
? orderSets.map(
|
? orderSets.map(
|
||||||
|
|
@ -175,7 +201,10 @@ export const OrderSets: React.FC<OrderSetProps> = ({
|
||||||
</Text>
|
</Text>
|
||||||
}
|
}
|
||||||
sections={[
|
sections={[
|
||||||
{ color: "orange", value: probability * 100 },
|
{
|
||||||
|
color: "orange",
|
||||||
|
value: probability * 100,
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
@ -187,7 +216,7 @@ export const OrderSets: React.FC<OrderSetProps> = ({
|
||||||
</Text>
|
</Text>
|
||||||
) : null}
|
) : null}
|
||||||
<Flex justify="end" align="flex-end" gap="sm">
|
<Flex justify="end" align="flex-end" gap="sm">
|
||||||
{orders.length > 0 ? (
|
{permissions?.can_details && orders.length > 0 ? (
|
||||||
<DonutChart
|
<DonutChart
|
||||||
flex={1}
|
flex={1}
|
||||||
size={130}
|
size={130}
|
||||||
|
|
@ -196,11 +225,15 @@ export const OrderSets: React.FC<OrderSetProps> = ({
|
||||||
name,
|
name,
|
||||||
value: weight,
|
value: weight,
|
||||||
color:
|
color:
|
||||||
COLORS_ROTATION[idx % COLORS_ROTATION.length],
|
COLORS_ROTATION[
|
||||||
|
idx % COLORS_ROTATION.length
|
||||||
|
],
|
||||||
}))}
|
}))}
|
||||||
tooltipDataSource="segment"
|
tooltipDataSource="segment"
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
{permissions?.can_edit ? (
|
||||||
|
<>
|
||||||
<ConfirmDialogButton
|
<ConfirmDialogButton
|
||||||
buttonColor="red.8"
|
buttonColor="red.8"
|
||||||
buttonText="Delete"
|
buttonText="Delete"
|
||||||
|
|
@ -210,10 +243,16 @@ export const OrderSets: React.FC<OrderSetProps> = ({
|
||||||
>
|
>
|
||||||
<IconTrash />
|
<IconTrash />
|
||||||
</ConfirmDialogButton>
|
</ConfirmDialogButton>
|
||||||
<NavigateButton to={`/orders/${username}/${id}`}>
|
<NavigateButton
|
||||||
<IconPencil style={{ marginRight: "0.5rem" }} />
|
to={`/orders/${username}/${id}`}
|
||||||
|
>
|
||||||
|
<IconPencil
|
||||||
|
style={{ marginRight: "0.5rem" }}
|
||||||
|
/>
|
||||||
Edit
|
Edit
|
||||||
</NavigateButton>
|
</NavigateButton>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
@ -222,13 +261,29 @@ export const OrderSets: React.FC<OrderSetProps> = ({
|
||||||
)
|
)
|
||||||
: null}
|
: null}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
) : (
|
||||||
|
<Flex justify="center">
|
||||||
|
<Alert
|
||||||
|
variant="light"
|
||||||
|
color="orange"
|
||||||
|
title="Warning"
|
||||||
|
icon={<IconAlertTriangle />}
|
||||||
|
my="md"
|
||||||
|
w="40rem"
|
||||||
|
>
|
||||||
|
You are not authorized to view order pools for <b>{username}</b>.
|
||||||
|
</Alert>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{permissions?.can_edit ? (
|
||||||
<Box my="lg">
|
<Box my="lg">
|
||||||
<NavigateButton to={`/orders/${username}/new`}>
|
<NavigateButton to={`/orders/${username}/new`}>
|
||||||
<IconPlus style={{ marginRight: "0.5rem" }} />
|
<IconPlus style={{ marginRight: "0.5rem" }} />
|
||||||
New
|
New
|
||||||
</NavigateButton>
|
</NavigateButton>
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
) : null}
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,34 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Params, useLoaderData, useParams, Link } from "react-router";
|
import { Params, useLoaderData, useParams, Link } from "react-router";
|
||||||
import { OrderSetProps, OrderSets } from "./OrderSets";
|
import { OrderSetProps, OrderSets, OrderSetsResponse } from "./OrderSets";
|
||||||
import { ProfileVerification } from "./ProfileVerification";
|
import { ProfileVerification } from "./ProfileVerification";
|
||||||
import { Anchor, Title } from "@mantine/core";
|
import { Anchor, Title } from "@mantine/core";
|
||||||
|
|
||||||
export const subOrderSetsLoader = async ({
|
export const userOrderSetsLoader = async ({
|
||||||
params: { username },
|
params: { username },
|
||||||
}: {
|
}: {
|
||||||
params: Params<string>;
|
params: Params<string>;
|
||||||
}) => fetch(`/api/orders/${username}/sets`).then((response) => response.json());
|
}) => fetch(`/api/orders/${username}/sets`).then((response) => response.json());
|
||||||
|
|
||||||
export const SubOrderSets: React.FC = () => {
|
export const UserOrderSets: React.FC = () => {
|
||||||
const { username: sub_username } = useParams();
|
const { username: sub_username } = useParams();
|
||||||
const orderSets = useLoaderData<OrderSetProps["orderSets"]>();
|
const orderSets = useLoaderData<OrderSetsResponse>();
|
||||||
|
|
||||||
const [profile, setProfile] = React.useState<UserProfile | null>(null);
|
const [profile, setProfile] = React.useState<UserProfile | null>(null);
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
fetch(`/api/subs/${sub_username}`)
|
// fetch(`/api/subs/${sub_username}`).then(async (response) => {
|
||||||
.then((response) => response.json())
|
// if (response.ok) {
|
||||||
.then(setProfile);
|
// setProfile(await response.json());
|
||||||
|
// }
|
||||||
|
// });
|
||||||
}, [sub_username]);
|
}, [sub_username]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<OrderSets
|
<OrderSets
|
||||||
username={sub_username}
|
username={sub_username}
|
||||||
orderSets={orderSets}
|
orderSets={orderSets.pools}
|
||||||
|
permissions={orderSets.permissions}
|
||||||
linkBack={
|
linkBack={
|
||||||
<Anchor component={Link} to={`/dashboard/`}>
|
<Anchor component={Link} to={`/dashboard/`}>
|
||||||
Return to dashboard
|
Return to dashboard
|
||||||
|
|
@ -21,7 +21,7 @@ import "@mantine/notifications/styles.css";
|
||||||
import "@mantine/charts/styles.css";
|
import "@mantine/charts/styles.css";
|
||||||
|
|
||||||
import { Dashboard, subsListLoader } from "./Dashboard";
|
import { Dashboard, subsListLoader } from "./Dashboard";
|
||||||
import { SubOrderSets, subOrderSetsLoader } from "./SubOrderSets";
|
import { UserOrderSets, userOrderSetsLoader } from "./UserOrderSets";
|
||||||
import { OrderSet, orderSetLoader, orderSetAction } from "./OrderSet";
|
import { OrderSet, orderSetLoader, orderSetAction } from "./OrderSet";
|
||||||
import { UserContextProvider } from "./UserContext";
|
import { UserContextProvider } from "./UserContext";
|
||||||
import { Header } from "./Header";
|
import { Header } from "./Header";
|
||||||
|
|
@ -75,8 +75,8 @@ const router = createBrowserRouter([
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "orders/:username",
|
path: "orders/:username",
|
||||||
Component: SubOrderSets,
|
Component: UserOrderSets,
|
||||||
loader: subOrderSetsLoader,
|
loader: userOrderSetsLoader,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "orders/:username/new",
|
path: "orders/:username/new",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue