Add user management for activation, deactivation, and deletion

Introduce API endpoints and storage methods for setting user passwords, soft deactivation (hiding availability), and hard deletion (removing all associated future data).

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 3a22ac80-cd1d-4441-9e36-f24fc2f4c3de
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3478f7c3-db8c-4fca-9165-3adbdf1b5829/3a22ac80-cd1d-4441-9e36-f24fc2f4c3de/gBqmpbl
This commit is contained in:
spliceboti
2025-09-12 20:36:14 +00:00
parent 91706d07c7
commit 60b5735588
3 changed files with 118 additions and 5 deletions
+66
View File
@@ -51,6 +51,11 @@ export interface IStorage {
reactivateUser(id: string): Promise<void>;
makeAdmin(id: string): Promise<void>;
removeAdmin(id: string): Promise<void>;
setUserPassword(id: string, password: string, isTemporary?: boolean): Promise<void>;
deactivateUserSoft(id: string): Promise<void>;
deleteUserHard(id: string): Promise<void>;
getUserActiveStatus(id: string): Promise<boolean>;
createUserWithPassword(userData: InsertUser & { password: string, isTemporary?: boolean }): Promise<User>;
// Event operations
createEvent(event: InsertEvent): Promise<Event>;
@@ -149,6 +154,18 @@ export class DatabaseStorage implements IStorage {
return user;
}
async createUserWithPassword(userData: InsertUser & { password: string, isTemporary?: boolean }): Promise<User> {
const { password, isTemporary, ...userFields } = userData;
const [user] = await db.insert(users).values({
...userFields,
password,
tempPassword: isTemporary ? password : null,
needsPasswordChange: isTemporary || false,
isActive: true // Activate immediately when password is provided
}).returning();
return user;
}
async upsertUser(userData: UpsertUser): Promise<User> {
const [user] = await db
.insert(users)
@@ -193,6 +210,55 @@ export class DatabaseStorage implements IStorage {
await db.update(users).set({ role: "dj", updatedAt: new Date() }).where(eq(users.id, id));
}
async setUserPassword(id: string, password: string, isTemporary: boolean = false): Promise<void> {
await db.update(users).set({
password,
tempPassword: isTemporary ? password : null,
needsPasswordChange: isTemporary,
isActive: true, // Activate user when password is set
updatedAt: new Date()
}).where(eq(users.id, id));
}
async deactivateUserSoft(id: string): Promise<void> {
// Soft deactivation - hide from availability/scheduling but keep all data
await db.update(users).set({ isActive: false, updatedAt: new Date() }).where(eq(users.id, id));
}
async deleteUserHard(id: string): Promise<void> {
// Hard deletion - remove user and all future schedules/availability
const currentDate = new Date().toISOString().split('T')[0];
// Delete future availability
await db.delete(availability)
.where(and(eq(availability.djId, id), gte(availability.startDate, currentDate)));
// Delete future events (keep past events for historical purposes)
await db.delete(events)
.where(and(eq(events.djId, id), gte(events.date, currentDate)));
// Delete slot eligibility
await db.delete(slotEligibility).where(eq(slotEligibility.djId, id));
// Delete social links
await db.delete(socialLinks).where(eq(socialLinks.djId, id));
// Delete removal requests
await db.delete(removalRequests).where(eq(removalRequests.djId, id));
// Finally delete the user
await db.delete(users).where(eq(users.id, id));
}
async getUserActiveStatus(id: string): Promise<boolean> {
const [user] = await db.select({ isActive: users.isActive, password: users.password })
.from(users)
.where(eq(users.id, id));
// User is considered active if they have isActive=true AND have a password set
return user ? user.isActive && !!user.password : false;
}
// Event operations
async createEvent(event: InsertEvent): Promise<Event> {
const [newEvent] = await db.insert(events).values(event).returning();