mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-08-04 22:40:11 +00:00
feat: rename revokeInvite to deleteInvite and update related functionality
This commit is contained in:
@@ -249,7 +249,7 @@ export async function handleAdminListInvites(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DELETE /api/admin/invites/:code
|
// DELETE /api/admin/invites/:code
|
||||||
export async function handleAdminRevokeInvite(
|
export async function handleAdminDeleteInvite(
|
||||||
request: Request,
|
request: Request,
|
||||||
env: Env,
|
env: Env,
|
||||||
actorUser: User,
|
actorUser: User,
|
||||||
@@ -260,12 +260,14 @@ export async function handleAdminRevokeInvite(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const storage = new StorageService(env.DB);
|
const storage = new StorageService(env.DB);
|
||||||
const revoked = await storage.revokeInvite(code);
|
const deleted = await storage.deleteInvite(code);
|
||||||
if (!revoked) {
|
if (!deleted) {
|
||||||
return errorResponse('Invite not found or already inactive', 404);
|
return errorResponse('Invite not found', 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
await writeAuditLog(storage, actorUser.id, 'admin.invite.revoke', 'invite', null, null, request);
|
await writeAuditLog(storage, actorUser.id, 'admin.invite.delete', 'invite', null, {
|
||||||
|
code,
|
||||||
|
}, request);
|
||||||
return new Response(null, { status: 204 });
|
return new Response(null, { status: 204 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -4,7 +4,7 @@ import {
|
|||||||
handleAdminCreateInvite,
|
handleAdminCreateInvite,
|
||||||
handleAdminListInvites,
|
handleAdminListInvites,
|
||||||
handleAdminDeleteAllInvites,
|
handleAdminDeleteAllInvites,
|
||||||
handleAdminRevokeInvite,
|
handleAdminDeleteInvite,
|
||||||
handleAdminSetUserStatus,
|
handleAdminSetUserStatus,
|
||||||
handleAdminDeleteUser,
|
handleAdminDeleteUser,
|
||||||
handleAdminListAuditLogs,
|
handleAdminListAuditLogs,
|
||||||
@@ -52,7 +52,7 @@ export async function handleAdminRoute(
|
|||||||
const adminInviteMatch = path.match(/^\/api\/admin\/invites\/([^/]+)$/i);
|
const adminInviteMatch = path.match(/^\/api\/admin\/invites\/([^/]+)$/i);
|
||||||
if (adminInviteMatch && method === 'DELETE') {
|
if (adminInviteMatch && method === 'DELETE') {
|
||||||
const inviteCode = decodeURIComponent(adminInviteMatch[1]);
|
const inviteCode = decodeURIComponent(adminInviteMatch[1]);
|
||||||
return handleAdminRevokeInvite(request, env, actorUser, inviteCode);
|
return handleAdminDeleteInvite(request, env, actorUser, inviteCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
const adminUserStatusMatch = path.match(/^\/api\/admin\/users\/([a-f0-9-]+)\/status$/i);
|
const adminUserStatusMatch = path.match(/^\/api\/admin\/users\/([a-f0-9-]+)\/status$/i);
|
||||||
|
|||||||
@@ -151,11 +151,10 @@ export async function revertInviteUsed(db: D1Database, code: string, userId: str
|
|||||||
return (result.meta.changes ?? 0) > 0;
|
return (result.meta.changes ?? 0) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function revokeInvite(db: D1Database, code: string): Promise<boolean> {
|
export async function deleteInvite(db: D1Database, code: string): Promise<boolean> {
|
||||||
const now = new Date().toISOString();
|
|
||||||
const result = await db
|
const result = await db
|
||||||
.prepare("UPDATE invites SET status = 'revoked', updated_at = ? WHERE code = ? AND status = 'active'")
|
.prepare('DELETE FROM invites WHERE code = ?')
|
||||||
.bind(now, code)
|
.bind(code)
|
||||||
.run();
|
.run();
|
||||||
return (result.meta.changes ?? 0) > 0;
|
return (result.meta.changes ?? 0) > 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import {
|
|||||||
clearAuditLogs as clearStoredAuditLogs,
|
clearAuditLogs as clearStoredAuditLogs,
|
||||||
assignInviteUsedBy as assignStoredInviteUsedBy,
|
assignInviteUsedBy as assignStoredInviteUsedBy,
|
||||||
createInvite as createStoredInvite,
|
createInvite as createStoredInvite,
|
||||||
|
deleteInvite as deleteStoredInvite,
|
||||||
deleteAllInvites as deleteStoredInvites,
|
deleteAllInvites as deleteStoredInvites,
|
||||||
getInvite as findStoredInvite,
|
getInvite as findStoredInvite,
|
||||||
listAuditLogs as listStoredAuditLogs,
|
listAuditLogs as listStoredAuditLogs,
|
||||||
@@ -32,7 +33,6 @@ import {
|
|||||||
pruneAuditLogs as pruneStoredAuditLogs,
|
pruneAuditLogs as pruneStoredAuditLogs,
|
||||||
pruneAuditLogsToMax as pruneStoredAuditLogsToMax,
|
pruneAuditLogsToMax as pruneStoredAuditLogsToMax,
|
||||||
revertInviteUsed as revertStoredInviteUsed,
|
revertInviteUsed as revertStoredInviteUsed,
|
||||||
revokeInvite as revokeStoredInvite,
|
|
||||||
} from './storage-admin-repo';
|
} from './storage-admin-repo';
|
||||||
import {
|
import {
|
||||||
bulkDeleteFolders as deleteStoredFolders,
|
bulkDeleteFolders as deleteStoredFolders,
|
||||||
@@ -329,8 +329,8 @@ export class StorageService {
|
|||||||
return revertStoredInviteUsed(this.db, code, userId);
|
return revertStoredInviteUsed(this.db, code, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async revokeInvite(code: string): Promise<boolean> {
|
async deleteInvite(code: string): Promise<boolean> {
|
||||||
return revokeStoredInvite(this.db, code);
|
return deleteStoredInvite(this.db, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteAllInvites(): Promise<number> {
|
async deleteAllInvites(): Promise<number> {
|
||||||
|
|||||||
+1
-1
@@ -2039,7 +2039,7 @@ export default function App() {
|
|||||||
onDeleteAllInvites: adminActions.deleteAllInvites,
|
onDeleteAllInvites: adminActions.deleteAllInvites,
|
||||||
onToggleUserStatus: adminActions.toggleUserStatus,
|
onToggleUserStatus: adminActions.toggleUserStatus,
|
||||||
onDeleteUser: adminActions.deleteUser,
|
onDeleteUser: adminActions.deleteUser,
|
||||||
onRevokeInvite: adminActions.revokeInvite,
|
onDeleteInvite: adminActions.deleteInvite,
|
||||||
onLoadAuditLogs: (filters: AuditLogFilters) => listAuditLogs(authedFetch, filters),
|
onLoadAuditLogs: (filters: AuditLogFilters) => listAuditLogs(authedFetch, filters),
|
||||||
onLoadAuditLogSettings: () => getAuditLogSettings(authedFetch),
|
onLoadAuditLogSettings: () => getAuditLogSettings(authedFetch),
|
||||||
onSaveAuditLogSettings: (settings: AuditLogSettings) => saveAuditLogSettings(authedFetch, settings),
|
onSaveAuditLogSettings: (settings: AuditLogSettings) => saveAuditLogSettings(authedFetch, settings),
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ interface AdminPageProps {
|
|||||||
onDeleteAllInvites: () => Promise<void>;
|
onDeleteAllInvites: () => Promise<void>;
|
||||||
onToggleUserStatus: (userId: string, currentStatus: 'active' | 'banned') => Promise<void>;
|
onToggleUserStatus: (userId: string, currentStatus: 'active' | 'banned') => Promise<void>;
|
||||||
onDeleteUser: (userId: string) => Promise<void>;
|
onDeleteUser: (userId: string) => Promise<void>;
|
||||||
onRevokeInvite: (code: string) => Promise<void>;
|
onDeleteInvite: (code: string) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AdminPage(props: AdminPageProps) {
|
export default function AdminPage(props: AdminPageProps) {
|
||||||
@@ -184,11 +184,9 @@ export default function AdminPage(props: AdminPageProps) {
|
|||||||
>
|
>
|
||||||
<Clipboard size={14} className="btn-icon" /> {t('txt_copy_link')}
|
<Clipboard size={14} className="btn-icon" /> {t('txt_copy_link')}
|
||||||
</button>
|
</button>
|
||||||
{invite.status === 'active' && (
|
<button type="button" className="btn btn-danger" onClick={() => void props.onDeleteInvite(invite.code)}>
|
||||||
<button type="button" className="btn btn-danger" onClick={() => void props.onRevokeInvite(invite.code)}>
|
<Trash2 size={14} className="btn-icon" /> {t('txt_delete')}
|
||||||
<Trash2 size={14} className="btn-icon" /> {t('txt_revoke')}
|
|
||||||
</button>
|
</button>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ export interface AppMainRoutesProps {
|
|||||||
onDeleteAllInvites: () => Promise<void>;
|
onDeleteAllInvites: () => Promise<void>;
|
||||||
onToggleUserStatus: (userId: string, status: 'active' | 'banned') => Promise<void>;
|
onToggleUserStatus: (userId: string, status: 'active' | 'banned') => Promise<void>;
|
||||||
onDeleteUser: (userId: string) => Promise<void>;
|
onDeleteUser: (userId: string) => Promise<void>;
|
||||||
onRevokeInvite: (code: string) => Promise<void>;
|
onDeleteInvite: (code: string) => Promise<void>;
|
||||||
onLoadAuditLogs: (filters: AuditLogFilters) => Promise<AuditLogListResult>;
|
onLoadAuditLogs: (filters: AuditLogFilters) => Promise<AuditLogListResult>;
|
||||||
onLoadAuditLogSettings: () => Promise<AuditLogSettings>;
|
onLoadAuditLogSettings: () => Promise<AuditLogSettings>;
|
||||||
onSaveAuditLogSettings: (settings: AuditLogSettings) => Promise<AuditLogSettings>;
|
onSaveAuditLogSettings: (settings: AuditLogSettings) => Promise<AuditLogSettings>;
|
||||||
@@ -416,7 +416,7 @@ export default function AppMainRoutes(props: AppMainRoutesProps) {
|
|||||||
onDeleteAllInvites={props.onDeleteAllInvites}
|
onDeleteAllInvites={props.onDeleteAllInvites}
|
||||||
onToggleUserStatus={props.onToggleUserStatus}
|
onToggleUserStatus={props.onToggleUserStatus}
|
||||||
onDeleteUser={props.onDeleteUser}
|
onDeleteUser={props.onDeleteUser}
|
||||||
onRevokeInvite={props.onRevokeInvite}
|
onDeleteInvite={props.onDeleteInvite}
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useMemo } from 'preact/hooks';
|
import { useMemo } from 'preact/hooks';
|
||||||
import { createInvite, deleteAllInvites, deleteUser, revokeInvite, setUserStatus } from '@/lib/api/admin';
|
import { createInvite, deleteAllInvites, deleteInvite, deleteUser, setUserStatus } from '@/lib/api/admin';
|
||||||
import { t } from '@/lib/i18n';
|
import { t } from '@/lib/i18n';
|
||||||
import type { AppConfirmState } from '@/components/AppGlobalOverlays';
|
import type { AppConfirmState } from '@/components/AppGlobalOverlays';
|
||||||
import type { AuthedFetch } from '@/lib/api/shared';
|
import type { AuthedFetch } from '@/lib/api/shared';
|
||||||
@@ -45,14 +45,24 @@ export default function useAdminActions(options: UseAdminActionsOptions) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async revokeInvite(code: string) {
|
async deleteInvite(code: string) {
|
||||||
|
onSetConfirm({
|
||||||
|
title: t('txt_delete_invite'),
|
||||||
|
message: t('txt_delete_invite_confirm_message'),
|
||||||
|
danger: true,
|
||||||
|
onConfirm: () => {
|
||||||
|
onSetConfirm(null);
|
||||||
|
void (async () => {
|
||||||
try {
|
try {
|
||||||
await revokeInvite(authedFetch, code);
|
await deleteInvite(authedFetch, code);
|
||||||
await refetchInvites();
|
await refetchInvites();
|
||||||
onNotify('success', t('txt_invite_revoked'));
|
onNotify('success', t('txt_invite_deleted'));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
onNotify('error', error instanceof Error ? error.message : t('txt_revoke_invite_failed'));
|
onNotify('error', error instanceof Error ? error.message : t('txt_delete_invite_failed'));
|
||||||
}
|
}
|
||||||
|
})();
|
||||||
|
},
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
async deleteAllInvites() {
|
async deleteAllInvites() {
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ export async function createInvite(authedFetch: AuthedFetch, hours: number): Pro
|
|||||||
if (!resp.ok) throw new Error('Create invite failed');
|
if (!resp.ok) throw new Error('Create invite failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function revokeInvite(authedFetch: AuthedFetch, code: string): Promise<void> {
|
export async function deleteInvite(authedFetch: AuthedFetch, code: string): Promise<void> {
|
||||||
const resp = await authedFetch(`/api/admin/invites/${encodeURIComponent(code)}`, { method: 'DELETE' });
|
const resp = await authedFetch(`/api/admin/invites/${encodeURIComponent(code)}`, { method: 'DELETE' });
|
||||||
if (!resp.ok) throw new Error('Revoke invite failed');
|
if (!resp.ok) throw new Error('Delete invite failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteAllInvites(authedFetch: AuthedFetch): Promise<void> {
|
export async function deleteAllInvites(authedFetch: AuthedFetch): Promise<void> {
|
||||||
|
|||||||
@@ -1141,11 +1141,9 @@ export function createDemoMainRoutesProps(base: AppMainRoutesProps, notify: Noti
|
|||||||
state.setUsers((prev) => prev.filter((user) => user.id !== userId));
|
state.setUsers((prev) => prev.filter((user) => user.id !== userId));
|
||||||
notify('success', t('txt_user_deleted'));
|
notify('success', t('txt_user_deleted'));
|
||||||
},
|
},
|
||||||
onRevokeInvite: async (code) => {
|
onDeleteInvite: async (code) => {
|
||||||
state.setInvites((prev) => prev.map((invite) => (
|
state.setInvites((prev) => prev.filter((invite) => invite.code !== code));
|
||||||
invite.code === code ? { ...invite, status: 'inactive' } : invite
|
notify('success', t('txt_invite_deleted'));
|
||||||
)));
|
|
||||||
notify('success', t('txt_invite_revoked'));
|
|
||||||
},
|
},
|
||||||
onLoadAuditLogSettings: async () => ({ retentionDays: 90, maxEntries: null }),
|
onLoadAuditLogSettings: async () => ({ retentionDays: 90, maxEntries: null }),
|
||||||
onSaveAuditLogSettings: async (settings) => {
|
onSaveAuditLogSettings: async (settings) => {
|
||||||
|
|||||||
@@ -582,8 +582,12 @@ const en: Record<string, string> = {
|
|||||||
"txt_identity_details": "Identity Details",
|
"txt_identity_details": "Identity Details",
|
||||||
"txt_ie_browser": "IE Browser",
|
"txt_ie_browser": "IE Browser",
|
||||||
"txt_create_invite_failed": "Failed to create invite",
|
"txt_create_invite_failed": "Failed to create invite",
|
||||||
|
"txt_delete_invite": "Delete invite",
|
||||||
|
"txt_delete_invite_confirm_message": "Delete this invite code? This cannot be undone.",
|
||||||
|
"txt_delete_invite_failed": "Failed to delete invite",
|
||||||
"txt_invite_code_required": "Invite Code (Required)",
|
"txt_invite_code_required": "Invite Code (Required)",
|
||||||
"txt_invite_created": "Invite created",
|
"txt_invite_created": "Invite created",
|
||||||
|
"txt_invite_deleted": "Invite deleted",
|
||||||
"txt_invite_revoked": "Invite revoked",
|
"txt_invite_revoked": "Invite revoked",
|
||||||
"txt_revoke_invite_failed": "Failed to revoke invite",
|
"txt_revoke_invite_failed": "Failed to revoke invite",
|
||||||
"txt_invite_validity_hours": "Invite validity (hours)",
|
"txt_invite_validity_hours": "Invite validity (hours)",
|
||||||
@@ -1156,6 +1160,7 @@ const en: Record<string, string> = {
|
|||||||
"txt_log_action_admin_backup_settings_repair": "Repair backup settings",
|
"txt_log_action_admin_backup_settings_repair": "Repair backup settings",
|
||||||
"txt_log_action_admin_backup_settings_update": "Update backup settings",
|
"txt_log_action_admin_backup_settings_update": "Update backup settings",
|
||||||
"txt_log_action_admin_invite_create": "Create invite",
|
"txt_log_action_admin_invite_create": "Create invite",
|
||||||
|
"txt_log_action_admin_invite_delete": "Delete invite",
|
||||||
"txt_log_action_admin_invite_delete_all": "Clear invites",
|
"txt_log_action_admin_invite_delete_all": "Clear invites",
|
||||||
"txt_log_action_admin_invite_revoke": "Revoke invite",
|
"txt_log_action_admin_invite_revoke": "Revoke invite",
|
||||||
"txt_log_action_admin_user_delete": "Delete user",
|
"txt_log_action_admin_user_delete": "Delete user",
|
||||||
|
|||||||
@@ -582,8 +582,12 @@ const es: Record<string, string> = {
|
|||||||
"txt_identity_details": "Detalles de identidad",
|
"txt_identity_details": "Detalles de identidad",
|
||||||
"txt_ie_browser": "Navegador Internet Explorer",
|
"txt_ie_browser": "Navegador Internet Explorer",
|
||||||
"txt_create_invite_failed": "Error al crear invitación",
|
"txt_create_invite_failed": "Error al crear invitación",
|
||||||
|
"txt_delete_invite": "Eliminar invitación",
|
||||||
|
"txt_delete_invite_confirm_message": "¿Eliminar este código de invitación? Esta acción no se puede deshacer.",
|
||||||
|
"txt_delete_invite_failed": "Error al eliminar invitación",
|
||||||
"txt_invite_code_required": "Código de invitación (obligatorio)",
|
"txt_invite_code_required": "Código de invitación (obligatorio)",
|
||||||
"txt_invite_created": "Invitación creada",
|
"txt_invite_created": "Invitación creada",
|
||||||
|
"txt_invite_deleted": "Invitación eliminada",
|
||||||
"txt_invite_revoked": "Invitación revocada",
|
"txt_invite_revoked": "Invitación revocada",
|
||||||
"txt_revoke_invite_failed": "Error al revocar invitación",
|
"txt_revoke_invite_failed": "Error al revocar invitación",
|
||||||
"txt_invite_validity_hours": "Validez de la invitación en horas",
|
"txt_invite_validity_hours": "Validez de la invitación en horas",
|
||||||
@@ -1156,6 +1160,7 @@ const es: Record<string, string> = {
|
|||||||
"txt_log_action_admin_backup_settings_repair": "Repair backup settings",
|
"txt_log_action_admin_backup_settings_repair": "Repair backup settings",
|
||||||
"txt_log_action_admin_backup_settings_update": "Update backup settings",
|
"txt_log_action_admin_backup_settings_update": "Update backup settings",
|
||||||
"txt_log_action_admin_invite_create": "Create invite",
|
"txt_log_action_admin_invite_create": "Create invite",
|
||||||
|
"txt_log_action_admin_invite_delete": "Delete invite",
|
||||||
"txt_log_action_admin_invite_delete_all": "Clear invites",
|
"txt_log_action_admin_invite_delete_all": "Clear invites",
|
||||||
"txt_log_action_admin_invite_revoke": "Revoke invite",
|
"txt_log_action_admin_invite_revoke": "Revoke invite",
|
||||||
"txt_log_action_admin_user_delete": "Delete user",
|
"txt_log_action_admin_user_delete": "Delete user",
|
||||||
|
|||||||
@@ -582,8 +582,12 @@ const ru: Record<string, string> = {
|
|||||||
"txt_identity_details": "Данные личности",
|
"txt_identity_details": "Данные личности",
|
||||||
"txt_ie_browser": "IE-браузер",
|
"txt_ie_browser": "IE-браузер",
|
||||||
"txt_create_invite_failed": "Не удалось создать приглашение",
|
"txt_create_invite_failed": "Не удалось создать приглашение",
|
||||||
|
"txt_delete_invite": "Удалить приглашение",
|
||||||
|
"txt_delete_invite_confirm_message": "Удалить этот пригласительный код? Это действие нельзя отменить.",
|
||||||
|
"txt_delete_invite_failed": "Не удалось удалить приглашение",
|
||||||
"txt_invite_code_required": "Пригласительный код (обязательно)",
|
"txt_invite_code_required": "Пригласительный код (обязательно)",
|
||||||
"txt_invite_created": "Приглашение создано",
|
"txt_invite_created": "Приглашение создано",
|
||||||
|
"txt_invite_deleted": "Приглашение удалено",
|
||||||
"txt_invite_revoked": "Приглашение отозвано",
|
"txt_invite_revoked": "Приглашение отозвано",
|
||||||
"txt_revoke_invite_failed": "Не удалось отозвать приглашение",
|
"txt_revoke_invite_failed": "Не удалось отозвать приглашение",
|
||||||
"txt_invite_validity_hours": "Срок действия приглашения (часы)",
|
"txt_invite_validity_hours": "Срок действия приглашения (часы)",
|
||||||
@@ -1156,6 +1160,7 @@ const ru: Record<string, string> = {
|
|||||||
"txt_log_action_admin_backup_settings_repair": "Repair backup settings",
|
"txt_log_action_admin_backup_settings_repair": "Repair backup settings",
|
||||||
"txt_log_action_admin_backup_settings_update": "Update backup settings",
|
"txt_log_action_admin_backup_settings_update": "Update backup settings",
|
||||||
"txt_log_action_admin_invite_create": "Create invite",
|
"txt_log_action_admin_invite_create": "Create invite",
|
||||||
|
"txt_log_action_admin_invite_delete": "Delete invite",
|
||||||
"txt_log_action_admin_invite_delete_all": "Clear invites",
|
"txt_log_action_admin_invite_delete_all": "Clear invites",
|
||||||
"txt_log_action_admin_invite_revoke": "Revoke invite",
|
"txt_log_action_admin_invite_revoke": "Revoke invite",
|
||||||
"txt_log_action_admin_user_delete": "Delete user",
|
"txt_log_action_admin_user_delete": "Delete user",
|
||||||
|
|||||||
@@ -582,8 +582,12 @@ const zhCN: Record<string, string> = {
|
|||||||
"txt_identity_details": "身份详情",
|
"txt_identity_details": "身份详情",
|
||||||
"txt_ie_browser": "IE 浏览器",
|
"txt_ie_browser": "IE 浏览器",
|
||||||
"txt_create_invite_failed": "创建邀请码失败",
|
"txt_create_invite_failed": "创建邀请码失败",
|
||||||
|
"txt_delete_invite": "删除邀请码",
|
||||||
|
"txt_delete_invite_confirm_message": "确定删除该邀请码吗?删除后无法恢复。",
|
||||||
|
"txt_delete_invite_failed": "删除邀请码失败",
|
||||||
"txt_invite_code_required": "邀请码(必填)",
|
"txt_invite_code_required": "邀请码(必填)",
|
||||||
"txt_invite_created": "邀请码已创建",
|
"txt_invite_created": "邀请码已创建",
|
||||||
|
"txt_invite_deleted": "邀请码已删除",
|
||||||
"txt_invite_revoked": "邀请码已撤销",
|
"txt_invite_revoked": "邀请码已撤销",
|
||||||
"txt_revoke_invite_failed": "撤销邀请码失败",
|
"txt_revoke_invite_failed": "撤销邀请码失败",
|
||||||
"txt_invite_validity_hours": "邀请码有效期(小时)",
|
"txt_invite_validity_hours": "邀请码有效期(小时)",
|
||||||
@@ -1156,6 +1160,7 @@ const zhCN: Record<string, string> = {
|
|||||||
"txt_log_action_admin_backup_settings_repair": "修复备份设置",
|
"txt_log_action_admin_backup_settings_repair": "修复备份设置",
|
||||||
"txt_log_action_admin_backup_settings_update": "更新备份设置",
|
"txt_log_action_admin_backup_settings_update": "更新备份设置",
|
||||||
"txt_log_action_admin_invite_create": "创建邀请",
|
"txt_log_action_admin_invite_create": "创建邀请",
|
||||||
|
"txt_log_action_admin_invite_delete": "删除邀请",
|
||||||
"txt_log_action_admin_invite_delete_all": "清空邀请",
|
"txt_log_action_admin_invite_delete_all": "清空邀请",
|
||||||
"txt_log_action_admin_invite_revoke": "撤销邀请",
|
"txt_log_action_admin_invite_revoke": "撤销邀请",
|
||||||
"txt_log_action_admin_user_delete": "删除用户",
|
"txt_log_action_admin_user_delete": "删除用户",
|
||||||
|
|||||||
@@ -582,8 +582,12 @@ const zhTW: Record<string, string> = {
|
|||||||
"txt_identity_details": "身份詳情",
|
"txt_identity_details": "身份詳情",
|
||||||
"txt_ie_browser": "IE 瀏覽器",
|
"txt_ie_browser": "IE 瀏覽器",
|
||||||
"txt_create_invite_failed": "創建邀請碼失敗",
|
"txt_create_invite_failed": "創建邀請碼失敗",
|
||||||
|
"txt_delete_invite": "刪除邀請碼",
|
||||||
|
"txt_delete_invite_confirm_message": "確定刪除此邀請碼嗎?刪除後無法復原。",
|
||||||
|
"txt_delete_invite_failed": "刪除邀請碼失敗",
|
||||||
"txt_invite_code_required": "邀請碼(必填)",
|
"txt_invite_code_required": "邀請碼(必填)",
|
||||||
"txt_invite_created": "邀請碼已創建",
|
"txt_invite_created": "邀請碼已創建",
|
||||||
|
"txt_invite_deleted": "邀請碼已刪除",
|
||||||
"txt_invite_revoked": "邀請碼已撤銷",
|
"txt_invite_revoked": "邀請碼已撤銷",
|
||||||
"txt_revoke_invite_failed": "撤銷邀請碼失敗",
|
"txt_revoke_invite_failed": "撤銷邀請碼失敗",
|
||||||
"txt_invite_validity_hours": "邀請碼有效期(小時)",
|
"txt_invite_validity_hours": "邀請碼有效期(小時)",
|
||||||
@@ -1156,6 +1160,7 @@ const zhTW: Record<string, string> = {
|
|||||||
"txt_log_action_admin_backup_settings_repair": "修復備份設定",
|
"txt_log_action_admin_backup_settings_repair": "修復備份設定",
|
||||||
"txt_log_action_admin_backup_settings_update": "更新備份設定",
|
"txt_log_action_admin_backup_settings_update": "更新備份設定",
|
||||||
"txt_log_action_admin_invite_create": "建立邀請",
|
"txt_log_action_admin_invite_create": "建立邀請",
|
||||||
|
"txt_log_action_admin_invite_delete": "刪除邀請",
|
||||||
"txt_log_action_admin_invite_delete_all": "清空邀請",
|
"txt_log_action_admin_invite_delete_all": "清空邀請",
|
||||||
"txt_log_action_admin_invite_revoke": "撤銷邀請",
|
"txt_log_action_admin_invite_revoke": "撤銷邀請",
|
||||||
"txt_log_action_admin_user_delete": "刪除使用者",
|
"txt_log_action_admin_user_delete": "刪除使用者",
|
||||||
|
|||||||
Reference in New Issue
Block a user