import OrderedObject from "./OrderedObject.js" const argon2 = require("argon2") const { z } = require("zod") export default class Members extends OrderedObject { addressSchema = z.object({ address1: z.string(), address2: z.string().optional(), zip: z.string().regex(/^\d{5}(-\d{4})?$/), state: z.string(), city: z.string() }) schema = z.object({ email: z.string().email(), firstName: z.string(), lastName: z.string(), password: z.string(), tokenUsed: z.string().regex( /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, "Invalid UUID" ), joined: z.string(), address: this.addressSchema, }) isHashed = (s) => {return s.startsWith("$argon2")} save(member) { let id = `MEMBER-${member.email}` let result = this.schema.safeParse(member) if(result.success) { try { super.add(id, member) } catch(e) { console.error(e) throw e } } else { console.error("Failed parsing member: ", result.error) throw new global.ServerError(400, "Invalid Member Data!: "); } } async add(newMember, tokenID) { newMember.tokenUsed = tokenID const hash = await argon2.hash(newMember.password); newMember.password = hash newMember.joined = this.currentTime() this.save(newMember) } getByEmail(email) { return super.get(`MEMBER-${email}`) } currentTime() { const now = new Date(); const month = String(now.getMonth() + 1).padStart(2, "0"); const day = String(now.getDate()).padStart(2, "0"); const year = now.getFullYear(); let hours = now.getHours(); const ampm = hours >= 12 ? "pm" : "am"; hours = hours % 12 || 12; // convert to 12-hour format const minutes = String(now.getMinutes()).padStart(2, "0"); const seconds = String(now.getSeconds()).padStart(2, "0"); const ms = String(now.getMilliseconds()).padStart(4, "0"); // 4-digit like "5838" return `${month}.${day}.${year}-${hours}:${minutes}:${seconds}${ms}${ampm}`; } }