import path from 'path'; import fs from 'fs'; import argon2 from 'argon2'; import { z } from 'zod'; import sql from '../sql.js'; export default class Member { schema = z.object({ email: z.string().email(), firstName: z.string(), lastName: z.string(), password: z.string(), apps: z.array(z.string()) }); isHashed = (s) => s.startsWith("$argon2"); async add(newMember, networkId = null) { if (!this.isHashed(newMember.password)) { newMember.password = await argon2.hash(newMember.password); } const result = this.schema.safeParse(newMember); if (!result.success) { console.error(result.error); throw new global.ServerError(400, "Invalid Member Data!"); } try { const [member] = await sql` INSERT INTO members ${sql({ email: newMember.email, first_name: newMember.firstName, last_name: newMember.lastName, password: newMember.password, apps: newMember.apps ?? ['Dashboard'] })} RETURNING * `; if (networkId) { await sql` INSERT INTO member_network ${sql({ member_id: member.id, network_id: networkId, type: 'IN' })} `; } return member; } catch (e) { console.error(e); throw new global.ServerError(400, "Failed to add member!"); } } async getByID(id) { const [member] = await sql` SELECT * FROM members WHERE id = ${id} `; return member ?? null; } async getByEmail(email) { const [member] = await sql` SELECT * FROM members WHERE email = ${email} `; return member ?? null; } async getByNetwork(networkId) { return await sql` SELECT m.* FROM members m JOIN member_network mn ON mn.member_id = m.id WHERE mn.network_id = ${networkId} `; } async getPersonalData(id) { const filePath = path.join(global.db.PERSONAL_DATA_PATH, id, "db.json"); const raw = await fs.promises.readFile(filePath, "utf8"); return raw.trim() ? JSON.parse(raw) : []; } }