fix: admin/accounts: wrong message displayed in case of expired account
Massimo Melina committed
Apr 15, 2025 at 22:36 UTC
34070227a9936997e04d24e5b11bff4ba2f91b8d
5 files changed
+17
-8
admin/src/AccountForm.ts
+5
-2
@@ -69,8 +69,11 @@ export default function AccountForm({ account, done, groups, addToBar, reload }:
69
getError: (x, { values }) => (x||'') !== (values.password||'') && "Enter same password" },
70
71
{ k: 'disabled', comp: BoolField, fromField: x=>!x, toField: x=>!x, label: "Enabled", xs: 12, sm: 6, lg: 8,
72
- helperText: !values.disabled && values.canLogin === false ? h(Box, { color: 'warning.main', component: 'span' }, "Login is prevented because all of its groups are disabled")
73
- : "Login is prevented if account is disabled, or all its groups are disabled" },
72
+ helperText: values.disabled || values.canLogin !== false ? "Login is prevented if account is disabled, or all its groups are disabled"
73
+ : h(Box, { color: 'warning.main', component: 'span' },
74
+ new Date(account.expire!) < new Date() ? "Login is prevented because account is expired" // use account instead of values, so to use the value currently applied
75
+ : "Login is prevented because all of its groups are disabled")
76
+ },
77
{ k: 'ignore_limits', comp: BoolField, xs: 12, sm: 6, lg: 4,
78
helperText: values.ignore_limits ? "Speed limits don't apply to this account" : "Speed limits apply to this account" },
79
admin/src/AccountsPage.ts
+2
-2
@@ -6,7 +6,7 @@ import { Alert, Box, Card, CardContent, Grid, List, ListItem, ListItemText, Typo
6
import {
7
AccountTree, ChevronRight, Close, Delete, DoNotDisturb, ExpandMore, Group, MilitaryTech, Person, PersonAdd, Schedule
8
} from '@mui/icons-material'
9
-import { newDialog, with_, md } from './misc'
9
+import { newDialog, with_, md, Jsonify } from './misc'
10
import { Btn, Flex, IconBtn, iconTooltip, reloadBtn, useBreakpoint, useToggleButton } from './mui'
11
import { TreeItem, TreeView } from '@mui/x-tree-view'
12
import MenuButton from './MenuButton'
@@ -17,7 +17,7 @@ import { state, useSnapState } from './state'
17
import { importAccountsCsv } from './importAccountsCsv'
18
import apiAccounts from '../../src/api.accounts'
19
20
-export type Account = ReturnType<typeof apiAccounts.get_accounts>['list'][0]
20
+export type Account = Jsonify<ReturnType<typeof apiAccounts.get_accounts>['list'][0]>
21
22
export default function AccountsPage() {
23
const { username, accountsAsTree } = useSnapState()
shared/api.ts
+4
-3
@@ -2,8 +2,9 @@
2
3
import _ from 'lodash';
4
import { useCallback, useEffect, useMemo, useRef } from 'react';
5
-import { Callback, Dict, Falsy, getPrefixUrl, pendingPromise, useStateMounted, wait,
6
- buildUrlQueryString, } from '.'
5
+import {
6
+ Callback, Dict, Falsy, getPrefixUrl, pendingPromise, useStateMounted, wait, buildUrlQueryString, Jsonify,
7
+} from '.'
8
import { BetterEventEmitter } from '../src/events'
9
10
export const API_URL = '/~/api/'
@@ -84,7 +85,7 @@ export class ApiError extends Error {
85
86
export type UseApi<T=unknown> = ReturnType<typeof useApi<T>>
87
export function useApi<T=any>(cmd: string | Falsy, params?: object, options: ApiCallOptions={}) {
87
- const [data, setData, getData] = useStateMounted<Awaited<ReturnType<typeof apiCall<T>>> | undefined>(undefined)
88
+ const [data, setData, getData] = useStateMounted<Jsonify<Awaited<ReturnType<typeof apiCall<T>>>> | undefined>(undefined)
89
const [error, setError] = useStateMounted<Error | undefined>(undefined)
90
const [forcer, setForcer] = useStateMounted(0)
91
const [loading, setLoading, getLoading] = useStateMounted<undefined | ReturnType<typeof apiCall>>(undefined)
src/cross.ts
+5
@@ -59,6 +59,11 @@ export type Who = typeof WHO_ANYONE
59
| WhoObject
60
| AccountList // use false instead of empty array to keep the type boolean-able
61
export interface WhoObject { this?: Who, children?: Who }
62
+export type Jsonify<T> = T extends string | number | boolean | null | undefined ? T : // undefined is necessary to preserve union types, like number|undefined
63
+ T extends Date ? string :
64
+ T extends (infer U)[] ? Jsonify<U>[] :
65
+ T extends object ? { [K in keyof T]: Jsonify<T[K]> } :
66
+ never
67
68
export const defaultPerms: Required<VfsPerms> = {
69
can_see: 'can_read',
src/middlewares.ts
+1
-1
@@ -17,7 +17,7 @@ import { app } from './index'
17
import events from './events'
18
19
const forceHttps = defineConfig('force_https', true)
20
-const ignoreProxies = defineConfig('ignore_proxies', false)
20
+defineConfig('ignore_proxies', false)
21
const allowAuthorizationHeader = defineConfig('authorization_header', true)
22
export const sessionDuration = defineConfig('session_duration', Number(process.env.SESSION_DURATION) || DAY/1000,
23
v => v * 1000)