mirror of
https://github.com/AeThex-Corporation/AeThex-OS.git
synced 2026-04-18 14:27:20 +00:00
Introduces authentication via JWT, session management with CSRF protection, and new admin routes for managing users, projects, and monitoring security. Enhances dashboard and home pages with dynamic metrics fetched from the backend. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 279f1558-c0e3-40e4-8217-be7e9f4c6eca Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Event-Id: dcd55177-c240-4288-8fc0-652032c758f2 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/b984cb14-1d19-4944-922b-bc79e821ed35/279f1558-c0e3-40e4-8217-be7e9f4c6eca/2riq6Ir Replit-Helium-Checkpoint-Created: true
149 lines
4 KiB
TypeScript
149 lines
4 KiB
TypeScript
import { type User, type Profile, type Project } from "@shared/schema";
|
|
import { supabase } from "./supabase";
|
|
|
|
export interface IStorage {
|
|
// Users
|
|
getUser(id: string): Promise<User | undefined>;
|
|
getUserByUsername(username: string): Promise<User | undefined>;
|
|
|
|
// Profiles
|
|
getProfiles(): Promise<Profile[]>;
|
|
getProfile(id: string): Promise<Profile | undefined>;
|
|
getProfileByUsername(username: string): Promise<Profile | undefined>;
|
|
updateProfile(id: string, data: Partial<Profile>): Promise<Profile | undefined>;
|
|
|
|
// Projects
|
|
getProjects(): Promise<Project[]>;
|
|
getProject(id: string): Promise<Project | undefined>;
|
|
|
|
// Metrics
|
|
getMetrics(): Promise<{
|
|
totalProfiles: number;
|
|
totalProjects: number;
|
|
onlineUsers: number;
|
|
verifiedUsers: number;
|
|
totalXP: number;
|
|
avgLevel: number;
|
|
}>;
|
|
}
|
|
|
|
export class SupabaseStorage implements IStorage {
|
|
|
|
async getUser(id: string): Promise<User | undefined> {
|
|
const { data, error } = await supabase
|
|
.from('users')
|
|
.select('*')
|
|
.eq('id', id)
|
|
.single();
|
|
|
|
if (error || !data) return undefined;
|
|
return data as User;
|
|
}
|
|
|
|
async getUserByUsername(username: string): Promise<User | undefined> {
|
|
const { data, error } = await supabase
|
|
.from('users')
|
|
.select('*')
|
|
.eq('username', username)
|
|
.single();
|
|
|
|
if (error || !data) return undefined;
|
|
return data as User;
|
|
}
|
|
|
|
async getProfiles(): Promise<Profile[]> {
|
|
const { data, error } = await supabase
|
|
.from('profiles')
|
|
.select('*')
|
|
.order('created_at', { ascending: false });
|
|
|
|
if (error) return [];
|
|
return data as Profile[];
|
|
}
|
|
|
|
async getProfile(id: string): Promise<Profile | undefined> {
|
|
const { data, error } = await supabase
|
|
.from('profiles')
|
|
.select('*')
|
|
.eq('id', id)
|
|
.single();
|
|
|
|
if (error || !data) return undefined;
|
|
return data as Profile;
|
|
}
|
|
|
|
async getProfileByUsername(username: string): Promise<Profile | undefined> {
|
|
const { data, error } = await supabase
|
|
.from('profiles')
|
|
.select('*')
|
|
.eq('username', username)
|
|
.single();
|
|
|
|
if (error || !data) return undefined;
|
|
return data as Profile;
|
|
}
|
|
|
|
async updateProfile(id: string, updates: Partial<Profile>): Promise<Profile | undefined> {
|
|
const { data, error } = await supabase
|
|
.from('profiles')
|
|
.update({ ...updates, updated_at: new Date().toISOString() })
|
|
.eq('id', id)
|
|
.select()
|
|
.single();
|
|
|
|
if (error || !data) return undefined;
|
|
return data as Profile;
|
|
}
|
|
|
|
async getProjects(): Promise<Project[]> {
|
|
const { data, error } = await supabase
|
|
.from('projects')
|
|
.select('*')
|
|
.order('created_at', { ascending: false });
|
|
|
|
if (error) return [];
|
|
return data as Project[];
|
|
}
|
|
|
|
async getProject(id: string): Promise<Project | undefined> {
|
|
const { data, error } = await supabase
|
|
.from('projects')
|
|
.select('*')
|
|
.eq('id', id)
|
|
.single();
|
|
|
|
if (error || !data) return undefined;
|
|
return data as Project;
|
|
}
|
|
|
|
async getMetrics(): Promise<{
|
|
totalProfiles: number;
|
|
totalProjects: number;
|
|
onlineUsers: number;
|
|
verifiedUsers: number;
|
|
totalXP: number;
|
|
avgLevel: number;
|
|
}> {
|
|
// Get profiles for metrics
|
|
const profiles = await this.getProfiles();
|
|
const projects = await this.getProjects();
|
|
|
|
const onlineUsers = profiles.filter(p => p.status === 'online').length;
|
|
const verifiedUsers = profiles.filter(p => p.is_verified).length;
|
|
const totalXP = profiles.reduce((sum, p) => sum + (p.total_xp || 0), 0);
|
|
const avgLevel = profiles.length > 0
|
|
? profiles.reduce((sum, p) => sum + (p.level || 1), 0) / profiles.length
|
|
: 1;
|
|
|
|
return {
|
|
totalProfiles: profiles.length,
|
|
totalProjects: projects.length,
|
|
onlineUsers,
|
|
verifiedUsers,
|
|
totalXP,
|
|
avgLevel: Math.round(avgLevel * 10) / 10,
|
|
};
|
|
}
|
|
}
|
|
|
|
export const storage = new SupabaseStorage();
|