Add database schema, encryption utilities, and local database service
- Implement `schema.ts` for SQLite schema creation, indexing, and sync metadata initialization. - Develop `encryption.ts` with AES-256-GCM encryption utilities for securing database data. - Add `database.service.ts` to manage CRUD operations with encryption support, user-specific databases, and schema initialization. - Integrate book, chapter, and character operations with encrypted content handling and sync preparation.
This commit is contained in:
153
electron/database/mappers/user.mapper.ts
Normal file
153
electron/database/mappers/user.mapper.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* TypeScript interfaces (copied from lib/models for type safety)
|
||||
*/
|
||||
|
||||
export interface Subscription {
|
||||
subType: string;
|
||||
subTier: number;
|
||||
status: boolean;
|
||||
}
|
||||
|
||||
export interface UserProps {
|
||||
id: string;
|
||||
name: string;
|
||||
lastName: string;
|
||||
username: string;
|
||||
authorName?: string;
|
||||
email?: string;
|
||||
accountVerified: boolean;
|
||||
termsAccepted: boolean;
|
||||
aiUsage: number;
|
||||
apiKeys: {
|
||||
gemini: boolean;
|
||||
openai: boolean;
|
||||
anthropic: boolean;
|
||||
};
|
||||
books?: any[];
|
||||
guideTour?: { [key: string]: boolean }[];
|
||||
subscription?: Subscription[];
|
||||
writingLang: number;
|
||||
writingLevel: number;
|
||||
ritePoints: number;
|
||||
creditsBalance: number;
|
||||
groupId: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Database row types (snake_case from SQLite)
|
||||
*/
|
||||
export interface DBUser {
|
||||
user_id: string;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
username: string;
|
||||
email: string;
|
||||
origin_email: string;
|
||||
origin_username: string;
|
||||
author_name?: string;
|
||||
origin_author_name?: string;
|
||||
plateform: string;
|
||||
social_id?: string;
|
||||
user_group: number;
|
||||
password?: string;
|
||||
term_accepted: number;
|
||||
verify_code?: string;
|
||||
reg_date: number;
|
||||
account_verified: number;
|
||||
user_meta: string; // JSON containing apiKeys, guideTour, writingLang, writingLevel, aiUsage
|
||||
erite_points: number;
|
||||
stripe_customer_id?: string;
|
||||
credits_balance: number;
|
||||
synced?: number;
|
||||
}
|
||||
|
||||
interface UserMeta {
|
||||
apiKeys?: {
|
||||
gemini: boolean;
|
||||
openai: boolean;
|
||||
anthropic: boolean;
|
||||
};
|
||||
guideTour?: { [key: string]: boolean }[];
|
||||
subscription?: Subscription[];
|
||||
writingLang?: number;
|
||||
writingLevel?: number;
|
||||
aiUsage?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* MAPPERS: DB → TypeScript Interfaces
|
||||
*/
|
||||
|
||||
export function dbToUser(dbUser: DBUser): UserProps {
|
||||
let meta: UserMeta = {};
|
||||
try {
|
||||
meta = JSON.parse(dbUser.user_meta || '{}');
|
||||
} catch (error) {
|
||||
console.error('Failed to parse user_meta:', error);
|
||||
}
|
||||
|
||||
return {
|
||||
id: dbUser.user_id,
|
||||
name: dbUser.first_name,
|
||||
lastName: dbUser.last_name,
|
||||
username: dbUser.username,
|
||||
authorName: dbUser.author_name,
|
||||
email: dbUser.email,
|
||||
accountVerified: dbUser.account_verified === 1,
|
||||
termsAccepted: dbUser.term_accepted === 1,
|
||||
aiUsage: meta.aiUsage || 0,
|
||||
apiKeys: meta.apiKeys || {
|
||||
gemini: false,
|
||||
openai: false,
|
||||
anthropic: false
|
||||
},
|
||||
books: [], // Populated separately
|
||||
guideTour: meta.guideTour || [],
|
||||
subscription: meta.subscription || [],
|
||||
writingLang: meta.writingLang || 1,
|
||||
writingLevel: meta.writingLevel || 1,
|
||||
ritePoints: dbUser.erite_points,
|
||||
creditsBalance: dbUser.credits_balance,
|
||||
groupId: dbUser.user_group
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* MAPPERS: TypeScript Interfaces → DB
|
||||
*/
|
||||
|
||||
export function userToDb(user: UserProps, synced: number = 0): DBUser {
|
||||
const meta: UserMeta = {
|
||||
apiKeys: user.apiKeys,
|
||||
guideTour: user.guideTour,
|
||||
subscription: user.subscription,
|
||||
writingLang: user.writingLang,
|
||||
writingLevel: user.writingLevel,
|
||||
aiUsage: user.aiUsage
|
||||
};
|
||||
|
||||
return {
|
||||
user_id: user.id,
|
||||
first_name: user.name,
|
||||
last_name: user.lastName,
|
||||
username: user.username,
|
||||
email: user.email || '',
|
||||
origin_email: user.email || '',
|
||||
origin_username: user.username,
|
||||
author_name: user.authorName,
|
||||
origin_author_name: user.authorName,
|
||||
plateform: 'electron',
|
||||
social_id: undefined,
|
||||
user_group: user.groupId,
|
||||
password: undefined,
|
||||
term_accepted: user.termsAccepted ? 1 : 0,
|
||||
verify_code: undefined,
|
||||
reg_date: Date.now(),
|
||||
account_verified: user.accountVerified ? 1 : 0,
|
||||
user_meta: JSON.stringify(meta),
|
||||
erite_points: user.ritePoints,
|
||||
stripe_customer_id: undefined,
|
||||
credits_balance: user.creditsBalance,
|
||||
synced
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user