Introduce `avatarUrl` and `bio` fields in the user schema. Update repository, service, and controller to handle avatar uploads, processing, and bio updates. Add S3 integration for avatar storage and enhance user data handling for private and public profiles.
69 lines
2.3 KiB
TypeScript
69 lines
2.3 KiB
TypeScript
import {
|
|
boolean,
|
|
index,
|
|
pgEnum,
|
|
pgTable,
|
|
timestamp,
|
|
uuid,
|
|
varchar,
|
|
} from "drizzle-orm/pg-core";
|
|
import { pgpEncrypted, withAutomaticPgpDecrypt } from "./pgp";
|
|
|
|
export const userStatus = pgEnum("user_status", [
|
|
"active",
|
|
"verification",
|
|
"suspended",
|
|
"pending",
|
|
"deleted",
|
|
]);
|
|
|
|
export const users = pgTable(
|
|
"users",
|
|
{
|
|
uuid: uuid().primaryKey().defaultRandom(),
|
|
status: userStatus("status").default("pending").notNull(),
|
|
|
|
// Données Personnelles (PII) - Chiffrées nativement
|
|
email: pgpEncrypted("email").notNull(),
|
|
emailHash: varchar("email_hash", { length: 64 }).notNull().unique(), // Indexé pour recherche rapide et unicité
|
|
displayName: varchar("display_name", { length: 32 }),
|
|
|
|
username: varchar("username", { length: 32 }).notNull().unique(),
|
|
passwordHash: varchar("password_hash", { length: 100 }).notNull(),
|
|
avatarUrl: varchar("avatar_url", { length: 512 }),
|
|
bio: varchar("bio", { length: 255 }),
|
|
|
|
// Sécurité
|
|
twoFactorSecret: pgpEncrypted("two_factor_secret"),
|
|
isTwoFactorEnabled: boolean("is_two_factor_enabled").notNull().default(false),
|
|
|
|
// RGPD & Conformité
|
|
termsVersion: varchar("terms_version", { length: 16 }), // Version des CGU acceptées
|
|
privacyVersion: varchar("privacy_version", { length: 16 }), // Version de la Privacy Policy acceptée
|
|
gdprAcceptedAt: timestamp("gdpr_accepted_at", { withTimezone: true }),
|
|
|
|
// Dates de cycle de vie (Standards Entreprise)
|
|
lastLoginAt: timestamp("last_login_at", { withTimezone: true }),
|
|
createdAt: timestamp("created_at", { withTimezone: true })
|
|
.notNull()
|
|
.defaultNow(),
|
|
updatedAt: timestamp("updated_at", { withTimezone: true })
|
|
.notNull()
|
|
.defaultNow(),
|
|
deletedAt: timestamp("deleted_at", { withTimezone: true }), // Soft delete (Droit à l'oubli)
|
|
},
|
|
(table) => ({
|
|
uuidIdx: index("users_uuid_idx").on(table.uuid),
|
|
emailHashIdx: index("users_email_hash_idx").on(table.emailHash),
|
|
usernameIdx: index("users_username_idx").on(table.username),
|
|
statusIdx: index("users_status_idx").on(table.status),
|
|
}),
|
|
);
|
|
|
|
// Application du déchiffrement automatique pour les colonnes PGP
|
|
withAutomaticPgpDecrypt(users.email);
|
|
withAutomaticPgpDecrypt(users.twoFactorSecret);
|
|
|
|
export type UserInDb = typeof users.$inferSelect;
|
|
export type NewUserInDb = typeof users.$inferInsert;
|