Skip to content

Commit 29d92be

Browse files
Minor Update -> reset:data (PalisadoesFoundation#3304)
* Preserved Admin * clean * final --------- Co-authored-by: JaiPannu-IITI <[email protected]>
1 parent 0eef4d8 commit 29d92be

File tree

5 files changed

+31
-127
lines changed

5 files changed

+31
-127
lines changed

scripts/dbManagement/addSampleData.ts

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import path from "node:path";
22
import { fileURLToPath } from "node:url";
3-
import {
4-
disconnect,
5-
ensureAdministratorExists,
6-
insertCollections,
7-
pingDB,
8-
} from "./helpers";
3+
import { disconnect, insertCollections, pingDB } from "./helpers";
94

105
type Collection =
116
| "users"
@@ -35,16 +30,6 @@ export async function main(): Promise<void> {
3530
} catch (error: unknown) {
3631
throw new Error(`Database connection failed: ${error}`);
3732
}
38-
try {
39-
await ensureAdministratorExists();
40-
console.log("\x1b[32mSuccess:\x1b[0m Administrator setup complete\n");
41-
} catch (error: unknown) {
42-
console.error("\nError: Administrator creation failed", error);
43-
throw new Error(
44-
"\n\x1b[31mAdministrator access may be lost, try reimporting sample DB to restore access\x1b[0m\n",
45-
);
46-
}
47-
4833
try {
4934
await insertCollections(collections);
5035
console.log("\n\x1b[32mSuccess:\x1b[0m Sample Data added to the database");

scripts/dbManagement/helpers.ts

Lines changed: 27 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import fs from "node:fs/promises";
22
import path from "node:path";
33
import readline from "node:readline";
44
import { fileURLToPath } from "node:url";
5-
import { hash } from "@node-rs/argon2";
65
import { sql } from "drizzle-orm";
76
import type { AnyPgColumn, PgTable } from "drizzle-orm/pg-core";
87
import { drizzle } from "drizzle-orm/postgres-js";
@@ -15,7 +14,6 @@ import {
1514
envConfigSchema,
1615
envSchemaAjv,
1716
} from "src/envConfigSchema";
18-
import { uuidv7 } from "uuidv7";
1917

2018
const envConfig = envSchema<EnvConfig>({
2119
ajv: envSchemaAjv,
@@ -68,21 +66,40 @@ export async function askUserToContinue(question: string): Promise<boolean> {
6866
* Clears all tables in the database.
6967
*/
7068
export async function formatDatabase(): Promise<boolean> {
71-
type TableRow = { tablename: string };
69+
const adminEmail = envConfig.API_ADMINISTRATOR_USER_EMAIL_ADDRESS;
70+
71+
if (!adminEmail) {
72+
throw new Error(
73+
"Missing adminEmail environment variable. Aborting to prevent accidental deletion of all users.",
74+
);
75+
}
7276

77+
type TableRow = { tablename: string };
78+
const USERS_TABLE = "users";
7379
try {
7480
await db.transaction(async (tx) => {
7581
const tables: TableRow[] = await tx.execute(sql`
76-
SELECT tablename FROM pg_catalog.pg_tables
77-
WHERE schemaname = 'public'
78-
`);
79-
const tableNames = tables.map((row) => sql.identifier(row.tablename));
82+
SELECT tablename FROM pg_catalog.pg_tables
83+
WHERE schemaname = 'public'
84+
`);
85+
const tableNames = tables
86+
.map((row) => row.tablename)
87+
.filter((name) => name !== USERS_TABLE);
8088

8189
if (tableNames.length > 0) {
82-
await tx.execute(
83-
sql`TRUNCATE TABLE ${sql.join(tableNames, sql`, `)} RESTART IDENTITY CASCADE;`,
84-
);
90+
await tx.execute(sql`
91+
TRUNCATE TABLE ${sql.join(
92+
tableNames.map((table) => sql.identifier(table)),
93+
sql`, `,
94+
)}
95+
RESTART IDENTITY CASCADE;
96+
`);
8597
}
98+
99+
await tx.execute(sql`
100+
DELETE FROM ${sql.identifier(USERS_TABLE)}
101+
WHERE email != ${adminEmail};
102+
`);
86103
});
87104

88105
return true;
@@ -91,53 +108,6 @@ export async function formatDatabase(): Promise<boolean> {
91108
}
92109
}
93110

94-
export async function ensureAdministratorExists(): Promise<boolean> {
95-
const email = envConfig.API_ADMINISTRATOR_USER_EMAIL_ADDRESS;
96-
97-
if (!email) {
98-
throw new Error("API_ADMINISTRATOR_USER_EMAIL_ADDRESS is not defined.");
99-
}
100-
101-
const existingUser = await db.query.usersTable.findFirst({
102-
columns: { id: true, role: true },
103-
where: (fields, operators) => operators.eq(fields.emailAddress, email),
104-
});
105-
106-
if (existingUser) {
107-
if (existingUser.role !== "administrator") {
108-
await db
109-
.update(schema.usersTable)
110-
.set({ role: "administrator" })
111-
.where(sql`email_address = ${email}`);
112-
console.log(
113-
"\x1b[33mRole Change: Updated user role to administrator\x1b[0m\n",
114-
);
115-
} else {
116-
console.log("\x1b[32mFound:\x1b[0m Administrator user already exists");
117-
}
118-
return true;
119-
}
120-
121-
const userId = uuidv7();
122-
const password = envConfig.API_ADMINISTRATOR_USER_PASSWORD;
123-
if (!password) {
124-
throw new Error("API_ADMINISTRATOR_USER_PASSWORD is not defined.");
125-
}
126-
const passwordHash = await hash(password);
127-
128-
await db.insert(schema.usersTable).values({
129-
id: userId,
130-
emailAddress: email,
131-
name: envConfig.API_ADMINISTRATOR_USER_NAME || "",
132-
passwordHash,
133-
role: "administrator",
134-
isEmailAddressVerified: true,
135-
creatorId: userId,
136-
});
137-
138-
return true;
139-
}
140-
141111
export async function emptyMinioBucket(): Promise<boolean> {
142112
try {
143113
// List all objects in the bucket.

scripts/dbManagement/resetData.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {
44
askUserToContinue,
55
disconnect,
66
emptyMinioBucket,
7-
ensureAdministratorExists,
87
formatDatabase,
98
pingDB,
109
} from "./helpers";
@@ -26,13 +25,13 @@ export async function main(): Promise<void> {
2625
try {
2726
await formatDatabase();
2827
console.log("\n\x1b[32mSuccess:\x1b[0m Database formatted successfully");
28+
console.log("\x1b[32mSuccess:\x1b[0m Administrator preserved\n");
2929
} catch (error: unknown) {
3030
console.error(
3131
"\n\x1b[31mError: Database formatting failed\n\x1b[0m",
3232
error,
3333
);
3434
console.error("\n\x1b[33mRolled back to previous state\x1b[0m");
35-
console.error("\n\x1b[33mPreserving administrator access\x1b[0m");
3635
}
3736
try {
3837
await emptyMinioBucket();
@@ -43,15 +42,6 @@ export async function main(): Promise<void> {
4342
error,
4443
);
4544
}
46-
try {
47-
await ensureAdministratorExists();
48-
console.log("\x1b[32mSuccess:\x1b[0m Administrator access restored\n");
49-
} catch (error: unknown) {
50-
console.error("\nError: Administrator creation failed", error);
51-
console.error(
52-
"\n\x1b[31mAdministrator access may be lost, try reformatting DB to restore access\x1b[0m\n",
53-
);
54-
}
5545
} else {
5646
console.log("Operation cancelled");
5747
}

test/scripts/dbManagement/addSampleData.test.ts

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ suite("addSampleData main function tests", () => {
1010
test("should execute all operations successfully", async () => {
1111
// Arrange: simulate successful operations.
1212
const pingDBSpy = vi.spyOn(helpers, "pingDB").mockResolvedValue(true);
13-
const ensureAdminSpy = vi
14-
.spyOn(helpers, "ensureAdministratorExists")
15-
.mockResolvedValue(true);
1613
const insertCollectionsSpy = vi
1714
.spyOn(helpers, "insertCollections")
1815
.mockResolvedValue(true);
@@ -25,7 +22,6 @@ suite("addSampleData main function tests", () => {
2522

2623
// Assert: verify that each helper was called as expected.
2724
expect(pingDBSpy).toHaveBeenCalled();
28-
expect(ensureAdminSpy).toHaveBeenCalled();
2925
expect(insertCollectionsSpy).toHaveBeenCalledWith([
3026
"users",
3127
"organizations",
@@ -41,9 +37,6 @@ suite("addSampleData main function tests", () => {
4137
expect(consoleLogSpy).toHaveBeenCalledWith(
4238
expect.stringContaining("Database connected successfully"),
4339
);
44-
expect(consoleLogSpy).toHaveBeenCalledWith(
45-
expect.stringContaining("Administrator setup complete"),
46-
);
4740
expect(consoleLogSpy).toHaveBeenCalledWith(
4841
expect.stringContaining("Sample Data added to the database"),
4942
);
@@ -60,24 +53,9 @@ suite("addSampleData main function tests", () => {
6053
);
6154
});
6255

63-
test("should throw an error when ensureAdministratorExists fails", async () => {
64-
// Arrange: pingDB succeeds, but ensureAdministratorExists fails.
65-
vi.spyOn(helpers, "pingDB").mockResolvedValue(true);
66-
const errorMsg = "admin error";
67-
vi.spyOn(helpers, "ensureAdministratorExists").mockRejectedValue(
68-
new Error(errorMsg),
69-
);
70-
71-
// Act & Assert: main() should throw the specific error message.
72-
await expect(mainModule.main()).rejects.toThrow(
73-
"\n\x1b[31mAdministrator access may be lost, try reimporting sample DB to restore access\x1b[0m\n",
74-
);
75-
});
76-
7756
test("should throw an error when insertCollections fails", async () => {
78-
// Arrange: pingDB and ensureAdministratorExists succeed, but insertCollections fails.
57+
// Arrange: pingDB succeed, but insertCollections fails.
7958
vi.spyOn(helpers, "pingDB").mockResolvedValue(true);
80-
vi.spyOn(helpers, "ensureAdministratorExists").mockResolvedValue(true);
8159
const errorMsg = "insert error";
8260
vi.spyOn(helpers, "insertCollections").mockRejectedValue(
8361
new Error(errorMsg),

test/scripts/dbManagement/resetDB.test.ts

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ suite("resetData main function tests", () => {
3232
);
3333
});
3434

35-
test("should log errors for failing formatDatabase, emptyMinioBucket, and ensureAdministratorExists, but not throw", async () => {
35+
test("should log errors for failing formatDatabase, emptyMinioBucket but not throw", async () => {
3636
// Arrange: simulate user confirming and pingDB succeeding.
3737
vi.spyOn(helpers, "askUserToContinue").mockResolvedValue(true);
3838
vi.spyOn(helpers, "pingDB").mockResolvedValue(true);
@@ -43,9 +43,6 @@ suite("resetData main function tests", () => {
4343
vi.spyOn(helpers, "emptyMinioBucket").mockRejectedValue(
4444
new Error("minio error"),
4545
);
46-
vi.spyOn(helpers, "ensureAdministratorExists").mockRejectedValue(
47-
new Error("admin error"),
48-
);
4946

5047
const consoleErrorSpy = vi
5148
.spyOn(console, "error")
@@ -68,22 +65,10 @@ suite("resetData main function tests", () => {
6865
expect(consoleErrorSpy).toHaveBeenCalledWith(
6966
expect.stringContaining("Rolled back to previous state"),
7067
);
71-
expect(consoleErrorSpy).toHaveBeenCalledWith(
72-
expect.stringContaining("Preserving administrator access"),
73-
);
7468
expect(consoleErrorSpy).toHaveBeenCalledWith(
7569
expect.stringContaining("Error: Bucket formatting failed"),
7670
expect.any(Error),
7771
);
78-
expect(consoleErrorSpy).toHaveBeenCalledWith(
79-
expect.stringContaining("Error: Administrator creation failed"),
80-
expect.any(Error),
81-
);
82-
expect(consoleErrorSpy).toHaveBeenCalledWith(
83-
expect.stringContaining(
84-
"Administrator access may be lost, try reformatting DB to restore access",
85-
),
86-
);
8772
});
8873

8974
test("should log success messages when all operations succeed", async () => {
@@ -92,7 +77,6 @@ suite("resetData main function tests", () => {
9277
vi.spyOn(helpers, "pingDB").mockResolvedValue(true);
9378
vi.spyOn(helpers, "formatDatabase").mockResolvedValue(true);
9479
vi.spyOn(helpers, "emptyMinioBucket").mockResolvedValue(true);
95-
vi.spyOn(helpers, "ensureAdministratorExists").mockResolvedValue(true);
9680

9781
const consoleLogSpy = vi.spyOn(console, "log").mockImplementation(() => {});
9882

@@ -109,8 +93,5 @@ suite("resetData main function tests", () => {
10993
expect(consoleLogSpy).toHaveBeenCalledWith(
11094
expect.stringContaining("Bucket formatted successfully"),
11195
);
112-
expect(consoleLogSpy).toHaveBeenCalledWith(
113-
expect.stringContaining("Administrator access restored"),
114-
);
11596
});
11697
});

0 commit comments

Comments
 (0)