develpoer role
CI/CD Pipeline / Build and Push PocketBase Docker Image (push) Successful in 10s
CI/CD Pipeline / i18n Catalog Check (push) Successful in 43s
CI/CD Pipeline / Build and Push App Docker Image (push) Successful in 2m14s
CI/CD Pipeline / Deploy to Kubernetes (push) Successful in 8m29s
CI/CD Pipeline / Build and Push PocketBase Docker Image (push) Successful in 10s
CI/CD Pipeline / i18n Catalog Check (push) Successful in 43s
CI/CD Pipeline / Build and Push App Docker Image (push) Successful in 2m14s
CI/CD Pipeline / Deploy to Kubernetes (push) Successful in 8m29s
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { superTokensAdminFunctionMiddleware } from "@/utils/supertokens";
|
||||
import { superTokensDeveloperFunctionMiddleware } from "@/utils/supertokens";
|
||||
import { createServerFn } from "@tanstack/react-start";
|
||||
import { pbAdmin } from "@/lib/pocketbase/client";
|
||||
import { z } from "zod";
|
||||
@@ -17,7 +17,7 @@ const activitySearchParamsSchema = z.object({
|
||||
|
||||
export const searchActivities = createServerFn()
|
||||
.validator(activitySearchParamsSchema)
|
||||
.middleware([superTokensAdminFunctionMiddleware])
|
||||
.middleware([superTokensDeveloperFunctionMiddleware])
|
||||
.handler(async ({ data }) =>
|
||||
toServerResult<ActivityListResult>(async () => {
|
||||
const result = await pbAdmin.searchActivities(data);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { List, Text } from "@mantine/core";
|
||||
import { Plural, Trans, useLingui } from "@lingui/react/macro";
|
||||
import {
|
||||
DatabaseIcon,
|
||||
TreeStructureIcon,
|
||||
TrophyIcon,
|
||||
MedalIcon,
|
||||
@@ -10,12 +9,14 @@ import {
|
||||
} from "@phosphor-icons/react";
|
||||
import ListLink from "@/components/list-link";
|
||||
import ListButton from "@/components/list-button";
|
||||
import { useIsDeveloper } from "@/features/core/hooks/use-is-developer";
|
||||
import { getBadgeMigrationStatus, migrateBadgeProgress } from "@/features/badges/server";
|
||||
import { useServerQuery } from "@/lib/tanstack-query/hooks";
|
||||
import toast from "@/lib/sonner";
|
||||
|
||||
export const ToolsList = () => {
|
||||
const { t } = useLingui();
|
||||
const isDeveloper = useIsDeveloper();
|
||||
|
||||
const { data: migrationStatus, refetch: refetchMigrationStatus } = useServerQuery({
|
||||
queryKey: ["admin", "badge-migration-status"],
|
||||
@@ -51,11 +52,13 @@ export const ToolsList = () => {
|
||||
Icon={TrophyIcon}
|
||||
to="/admin/tournaments"
|
||||
/>
|
||||
<ListLink
|
||||
label={t`Telemetry`}
|
||||
Icon={PulseIcon}
|
||||
to="/admin/telemetry/usage"
|
||||
/>
|
||||
{isDeveloper && (
|
||||
<ListLink
|
||||
label={t`Telemetry`}
|
||||
Icon={PulseIcon}
|
||||
to="/admin/telemetry/usage"
|
||||
/>
|
||||
)}
|
||||
<ListLink
|
||||
label={t`Award Badges`}
|
||||
Icon={CrownIcon}
|
||||
@@ -91,13 +94,6 @@ export const ToolsList = () => {
|
||||
<Trans>Badge recalculation failed. Check the server logs.</Trans>
|
||||
</Text>
|
||||
)}
|
||||
<ListButton
|
||||
label={t`Open Pocketbase`}
|
||||
Icon={DatabaseIcon}
|
||||
onClick={() =>
|
||||
window.location.replace(process.env.POCKETBASE_URL! + "/_/")
|
||||
}
|
||||
/>
|
||||
<ListLink
|
||||
label={t`Bracket Preview`}
|
||||
Icon={TreeStructureIcon}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import { useAuth } from "@/contexts/auth-context";
|
||||
import { isDeveloperRole } from "../utils/roles";
|
||||
|
||||
export const useIsDeveloper = (): boolean => {
|
||||
const { roles } = useAuth();
|
||||
return isDeveloperRole(roles);
|
||||
};
|
||||
@@ -1,4 +1,8 @@
|
||||
export const ADMIN_ROLE = "Admin";
|
||||
export const DEVELOPER_ROLE = "Developer";
|
||||
|
||||
export const isDeveloperRole = (roles?: string[] | null): boolean =>
|
||||
!!roles?.includes(DEVELOPER_ROLE);
|
||||
|
||||
export const isAdminRole = (roles?: string[] | null): boolean =>
|
||||
!!roles?.includes(ADMIN_ROLE);
|
||||
!!roles?.includes(ADMIN_ROLE) || isDeveloperRole(roles);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Box, Title, Stack, Switch, Button, Text, Group } from "@mantine/core";
|
||||
import { Trans, useLingui } from "@lingui/react/macro";
|
||||
import { useWebPush } from "@/hooks/use-web-push";
|
||||
import { useAuth } from "@/contexts/auth-context";
|
||||
import { useIsAdmin } from "@/features/core/hooks/use-is-admin";
|
||||
import { useIsDeveloper } from "@/features/core/hooks/use-is-developer";
|
||||
import { updateUserTelemetryAlerts } from "@/features/settings/server";
|
||||
import toast from "@/lib/sonner";
|
||||
|
||||
@@ -40,7 +40,7 @@ const TelemetryAlertsSwitch = () => {
|
||||
export function NotificationsSection() {
|
||||
const { supported, configured, permission, subscribed, busy, enable, disable, sendTest } =
|
||||
useWebPush();
|
||||
const isAdmin = useIsAdmin();
|
||||
const isDeveloper = useIsDeveloper();
|
||||
const { t } = useLingui();
|
||||
|
||||
if (!supported || !configured) {
|
||||
@@ -99,7 +99,7 @@ export function NotificationsSection() {
|
||||
disabled={busy}
|
||||
label={t`Enable notifications on this device`}
|
||||
/>
|
||||
{subscribed && isAdmin && <TelemetryAlertsSwitch />}
|
||||
{subscribed && isDeveloper && <TelemetryAlertsSwitch />}
|
||||
{subscribed && (
|
||||
<Group>
|
||||
<Button
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createServerFn } from "@tanstack/react-start";
|
||||
import {
|
||||
superTokensAdminFunctionMiddleware,
|
||||
superTokensDeveloperFunctionMiddleware,
|
||||
superTokensFunctionMiddleware,
|
||||
} from "@/utils/supertokens";
|
||||
|
||||
@@ -145,7 +145,7 @@ export const updateUserAccentColor = createServerFn({ method: "POST" })
|
||||
|
||||
export const updateUserTelemetryAlerts = createServerFn({ method: "POST" })
|
||||
.validator((data: boolean) => data === true)
|
||||
.middleware([superTokensAdminFunctionMiddleware])
|
||||
.middleware([superTokensDeveloperFunctionMiddleware])
|
||||
.handler(async ({ context, data }) => {
|
||||
const { userAuthId, metadata } = context;
|
||||
if (!userAuthId) return;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { superTokensFunctionMiddleware, superTokensAdminFunctionMiddleware } from "@/utils/supertokens";
|
||||
import { isAdminRole } from "@/features/core/utils/roles";
|
||||
import { createServerFn } from "@tanstack/react-start";
|
||||
import { pbAdmin } from "@/lib/pocketbase/client";
|
||||
import { z } from "zod";
|
||||
@@ -35,8 +36,8 @@ export const createTeam = createServerFn()
|
||||
.handler(async ({ data, context }) =>
|
||||
toServerResult(async () => {
|
||||
const userId = context.userAuthId;
|
||||
const isAdmin = context.roles.includes("Admin");
|
||||
|
||||
const isAdmin = isAdminRole(context.roles);
|
||||
|
||||
//if (!isAdmin && !data.players.includes(userId)) {
|
||||
// throw new Error("You can only create teams that include yourself as a player");
|
||||
//}
|
||||
@@ -57,7 +58,7 @@ export const updateTeam = createServerFn()
|
||||
.handler(async ({ data: { id, updates }, context }) =>
|
||||
toServerResult(async () => {
|
||||
const userId = context.userAuthId;
|
||||
const isAdmin = context.roles.includes("Admin");
|
||||
const isAdmin = isAdminRole(context.roles);
|
||||
|
||||
const team = await pbAdmin.getTeam(id);
|
||||
if (!team) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createServerFn } from "@tanstack/react-start";
|
||||
import { z } from "zod";
|
||||
import { superTokensAdminFunctionMiddleware } from "@/utils/supertokens";
|
||||
import { superTokensDeveloperFunctionMiddleware } from "@/utils/supertokens";
|
||||
import { pbAdmin } from "@/lib/pocketbase/client";
|
||||
import { toServerResult } from "@/lib/tanstack-query/utils/to-server-result";
|
||||
import {
|
||||
@@ -37,7 +37,7 @@ const clientEventSearchSchema = z.object({
|
||||
|
||||
export const searchClientEvents = createServerFn()
|
||||
.validator(clientEventSearchSchema)
|
||||
.middleware([superTokensAdminFunctionMiddleware])
|
||||
.middleware([superTokensDeveloperFunctionMiddleware])
|
||||
.handler(async ({ data }) =>
|
||||
toServerResult<TelemetryListResult<ClientEvent>>(async () => {
|
||||
const result = await pbAdmin.searchClientEvents(data);
|
||||
@@ -58,7 +58,7 @@ const clientErrorSearchSchema = z.object({
|
||||
|
||||
export const searchClientErrors = createServerFn()
|
||||
.validator(clientErrorSearchSchema)
|
||||
.middleware([superTokensAdminFunctionMiddleware])
|
||||
.middleware([superTokensDeveloperFunctionMiddleware])
|
||||
.handler(async ({ data }) =>
|
||||
toServerResult<TelemetryListResult<ClientError>>(async () => {
|
||||
const result = await pbAdmin.searchClientErrors(data);
|
||||
@@ -77,7 +77,7 @@ const errorGroupsSchema = z.object({
|
||||
// not on the next rollup tick.
|
||||
export const getClientErrorGroups = createServerFn()
|
||||
.validator(errorGroupsSchema)
|
||||
.middleware([superTokensAdminFunctionMiddleware])
|
||||
.middleware([superTokensDeveloperFunctionMiddleware])
|
||||
.handler(async ({ data }) =>
|
||||
toServerResult<ClientErrorGroup[]>(async () => {
|
||||
const { from, to, includeResolved = false, limit = 50 } = data;
|
||||
@@ -141,7 +141,7 @@ export const getClientErrorGroups = createServerFn()
|
||||
|
||||
export const resolveClientErrorGroup = createServerFn({ method: "POST" })
|
||||
.validator(z.object({ groupHash: z.string(), resolved: z.boolean().optional() }))
|
||||
.middleware([superTokensAdminFunctionMiddleware])
|
||||
.middleware([superTokensDeveloperFunctionMiddleware])
|
||||
.handler(async ({ data }) =>
|
||||
toServerResult<{ updated: number }>(async () => {
|
||||
const updated = await pbAdmin.resolveErrorsByGroup(data.groupHash, data.resolved ?? true);
|
||||
@@ -158,7 +158,7 @@ const rollupRangeSchema = z.object({
|
||||
|
||||
export const getRollupRange = createServerFn()
|
||||
.validator(rollupRangeSchema)
|
||||
.middleware([superTokensAdminFunctionMiddleware])
|
||||
.middleware([superTokensDeveloperFunctionMiddleware])
|
||||
.handler(async ({ data }) =>
|
||||
toServerResult<RollupRow[]>(async () => pbAdmin.getRollupRange(data))
|
||||
);
|
||||
@@ -167,7 +167,7 @@ export const listTelemetryAlerts = createServerFn()
|
||||
.validator(
|
||||
z.object({ page: z.number().optional(), perPage: z.number().max(200).optional() })
|
||||
)
|
||||
.middleware([superTokensAdminFunctionMiddleware])
|
||||
.middleware([superTokensDeveloperFunctionMiddleware])
|
||||
.handler(async ({ data }) =>
|
||||
toServerResult<TelemetryListResult<TelemetryAlert>>(async () =>
|
||||
pbAdmin.listTelemetryAlerts(data.page, data.perPage)
|
||||
@@ -197,7 +197,7 @@ export const listSessions = createServerFn()
|
||||
perPage: z.number().max(100).optional(),
|
||||
})
|
||||
)
|
||||
.middleware([superTokensAdminFunctionMiddleware])
|
||||
.middleware([superTokensDeveloperFunctionMiddleware])
|
||||
.handler(async ({ data }) =>
|
||||
toServerResult<TelemetryListResult<SessionSummary>>(async () => {
|
||||
const { days = 7, page = 1, perPage = 30 } = data;
|
||||
@@ -285,7 +285,7 @@ const MAX_TIMELINE_ENTRIES = 500;
|
||||
|
||||
export const getSessionTimeline = createServerFn()
|
||||
.validator(z.object({ sessionId: z.string().min(8).max(64) }))
|
||||
.middleware([superTokensAdminFunctionMiddleware])
|
||||
.middleware([superTokensDeveloperFunctionMiddleware])
|
||||
.handler(async ({ data }) =>
|
||||
toServerResult<SessionTimeline>(async () => {
|
||||
const events = await pbAdmin.searchClientEvents({
|
||||
@@ -426,7 +426,7 @@ export const getSessionTimeline = createServerFn()
|
||||
);
|
||||
|
||||
export const getTelemetryRuntimeStatus = createServerFn()
|
||||
.middleware([superTokensAdminFunctionMiddleware])
|
||||
.middleware([superTokensDeveloperFunctionMiddleware])
|
||||
.handler(async () =>
|
||||
toServerResult<TelemetryRuntimeStatus>(async () => {
|
||||
ensureTelemetryScheduler();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { superTokensAdminFunctionMiddleware, superTokensFunctionMiddleware } from "@/utils/supertokens";
|
||||
import { isAdminRole } from "@/features/core/utils/roles";
|
||||
import { createServerFn } from "@tanstack/react-start";
|
||||
import { pbAdmin } from "@/lib/pocketbase/client";
|
||||
import { tournamentInputSchema, GroupStanding } from "@/features/tournaments/types";
|
||||
@@ -46,7 +47,7 @@ export const getTournament = createServerFn()
|
||||
.validator(z.string())
|
||||
.middleware([superTokensFunctionMiddleware])
|
||||
.handler(async ({ data: tournamentId, context }) => {
|
||||
const isAdmin = context.roles.includes("Admin");
|
||||
const isAdmin = isAdminRole(context.roles);
|
||||
return toServerResult(() => pbAdmin.getTournament(tournamentId, isAdmin));
|
||||
});
|
||||
|
||||
@@ -64,7 +65,7 @@ export const enrollTeam = createServerFn()
|
||||
.handler(async ({ data: { tournamentId, teamId }, context }) =>
|
||||
toServerResult(async () => {
|
||||
const userId = context.userAuthId;
|
||||
const isAdmin = context.roles.includes("Admin");
|
||||
const isAdmin = isAdminRole(context.roles);
|
||||
|
||||
const team = await pbAdmin.getTeam(teamId);
|
||||
if (!team) { throw new Error('Team not found'); }
|
||||
|
||||
Reference in New Issue
Block a user