Simple Managment webapp [LLM]

This commit is contained in:
2025-12-03 17:20:50 +01:00
parent b521f74951
commit e7f613b5dc
76 changed files with 20009 additions and 1 deletions

View File

@@ -0,0 +1,15 @@
export interface ApiError {
success: false;
error: number;
errhighlight: number;
message: string;
}
export function isApiError(response: unknown): response is ApiError {
return (
typeof response === 'object' &&
response !== null &&
'success' in response &&
(response as ApiError).success === false
);
}

View File

@@ -0,0 +1,43 @@
import { Subscription } from './subscription.model';
export interface Channel {
channel_id: string;
owner_user_id: string;
internal_name: string;
display_name: string;
description_name: string | null;
subscribe_key?: string;
send_key?: string;
timestamp_created: string;
timestamp_lastsent: string | null;
messages_sent: number;
}
export interface ChannelWithSubscription extends Channel {
subscription: Subscription | null;
}
export interface ChannelPreview {
channel_id: string;
owner_user_id: string;
internal_name: string;
display_name: string;
}
export type ChannelSelector = 'owned' | 'subscribed' | 'all' | 'subscribed_any' | 'all_any';
export interface CreateChannelRequest {
name: string;
subscribe?: boolean;
}
export interface UpdateChannelRequest {
display_name?: string;
description_name?: string;
subscribe_key?: string;
send_key?: string;
}
export interface ChannelListResponse {
channels: ChannelWithSubscription[];
}

View File

@@ -0,0 +1,33 @@
export type ClientType = 'ANDROID' | 'IOS' | 'LINUX' | 'MACOS' | 'WINDOWS';
export interface Client {
client_id: string;
user_id: string;
type: ClientType;
fcm_token: string;
timestamp_created: string;
agent_model: string;
agent_version: string;
name: string | null;
}
export interface ClientListResponse {
clients: Client[];
}
export function getClientTypeIcon(type: ClientType): string {
switch (type) {
case 'ANDROID':
return 'android';
case 'IOS':
return 'apple';
case 'MACOS':
return 'apple';
case 'WINDOWS':
return 'windows';
case 'LINUX':
return 'desktop';
default:
return 'desktop';
}
}

View File

@@ -0,0 +1,8 @@
export * from './user.model';
export * from './message.model';
export * from './channel.model';
export * from './subscription.model';
export * from './key-token.model';
export * from './client.model';
export * from './sender-name.model';
export * from './api-response.model';

View File

@@ -0,0 +1,51 @@
export interface KeyToken {
keytoken_id: string;
name: string;
timestamp_created: string;
timestamp_lastused: string | null;
owner_user_id: string;
all_channels: boolean;
channels: string[];
token?: string;
permissions: string;
messages_sent: number;
}
export interface KeyTokenPreview {
keytoken_id: string;
name: string;
}
export type TokenPermission = 'A' | 'CR' | 'CS' | 'UR';
export interface CreateKeyRequest {
name: string;
permissions: string;
all_channels?: boolean;
channels?: string[];
}
export interface UpdateKeyRequest {
name?: string;
permissions?: string;
all_channels?: boolean;
channels?: string[];
}
export interface KeyListResponse {
keys: KeyToken[];
}
export function parsePermissions(permissions: string): TokenPermission[] {
if (!permissions) return [];
return permissions.split(';').filter(p => p) as TokenPermission[];
}
export function hasPermission(permissions: string, required: TokenPermission): boolean {
const perms = parsePermissions(permissions);
return perms.includes(required) || perms.includes('A');
}
export function isAdminKey(key: KeyToken): boolean {
return hasPermission(key.permissions, 'A');
}

View File

@@ -0,0 +1,35 @@
export interface Message {
message_id: string;
sender_user_id: string;
channel_internal_name: string;
channel_owner_user_id: string;
channel_id: string;
sender_name: string | null;
sender_ip: string;
timestamp: string;
title: string;
content: string | null;
priority: number;
usr_message_id: string | null;
used_key_id: string;
trimmed: boolean;
}
export interface MessageListParams {
after?: string;
before?: string;
channel?: string;
priority?: number;
search?: string;
sender?: string;
subscription_status?: 'all' | 'confirmed' | 'unconfirmed';
trimmed?: boolean;
page_size?: number;
next_page_token?: string;
}
export interface MessageListResponse {
messages: Message[];
next_page_token: string;
page_size: number;
}

View File

@@ -0,0 +1,9 @@
export interface SenderNameStatistics {
name: string;
last_timestamp: string;
count: number;
}
export interface SenderNameListResponse {
senders: SenderNameStatistics[];
}

View File

@@ -0,0 +1,35 @@
export interface Subscription {
subscription_id: string;
subscriber_user_id: string;
channel_owner_user_id: string;
channel_id: string;
channel_internal_name: string;
timestamp_created: string;
confirmed: boolean;
}
export interface SubscriptionFilter {
direction?: 'outgoing' | 'incoming' | 'both';
confirmation?: 'all' | 'confirmed' | 'unconfirmed';
external?: 'all' | 'true' | 'false';
subscriber_user_id?: string;
channel_owner_user_id?: string;
next_page_token?: string;
page_size?: number;
}
export interface CreateSubscriptionRequest {
channel_id?: string;
channel_owner_user_id?: string;
channel_internal_name?: string;
}
export interface ConfirmSubscriptionRequest {
confirmed: boolean;
}
export interface SubscriptionListResponse {
subscriptions: Subscription[];
next_page_token?: string;
page_size?: number;
}

View File

@@ -0,0 +1,32 @@
export interface User {
user_id: string;
username: string | null;
timestamp_created: string;
timestamp_lastread: string | null;
timestamp_lastsent: string | null;
messages_sent: number;
is_pro: boolean;
quota_used: number;
quota_used_day: string | null;
}
export interface UserExtra {
quota_remaining: number;
quota_max: number;
quota_used: number;
default_channel: string;
max_body_size: number;
max_title_length: number;
default_priority: number;
max_channel_name_length: number;
max_channel_description_length: number;
max_sender_name_length: number;
max_user_message_id_length: number;
}
export interface UserWithExtra extends User, UserExtra {}
export interface UserPreview {
user_id: string;
username: string | null;
}