feat(auth): enhance authentication system with multi-user support and admin role management
- Implemented multi-user authentication with role-based access control. - Added environment variables for initial admin user setup. - Updated README and example environment file with new authentication options. - Introduced user and system configuration models in the database schema. - Enhanced authentication middleware to support user registration and role management. - Updated frontend to handle new authentication flows, including admin user creation and role updates.
This commit is contained in:
+57
-18
@@ -1,24 +1,63 @@
|
||||
import { test as base, expect } from "@playwright/test";
|
||||
import { ensurePageAuthenticated } from "./helpers/auth";
|
||||
|
||||
const AUTH_USERNAME = process.env.AUTH_USERNAME || "admin";
|
||||
const AUTH_PASSWORD = process.env.AUTH_PASSWORD || "admin";
|
||||
type Fixtures = {
|
||||
skipAuth: boolean;
|
||||
};
|
||||
|
||||
export const test = base;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Navigate to root to check if we need to login
|
||||
await page.goto("/");
|
||||
await page.waitForLoadState("domcontentloaded");
|
||||
|
||||
// If we see the login page, perform login
|
||||
const loginText = page.getByText("Sign in to access your drawings");
|
||||
if (await loginText.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
await page.getByLabel("Username").fill(AUTH_USERNAME);
|
||||
await page.getByLabel("Password").fill(AUTH_PASSWORD);
|
||||
await page.getByRole("button", { name: "Sign in" }).click();
|
||||
// Wait for dashboard to load
|
||||
await page.getByPlaceholder("Search drawings...").waitFor({ state: "visible", timeout: 15000 });
|
||||
}
|
||||
export const test = base.extend<Fixtures>({
|
||||
skipAuth: [false, { option: true }],
|
||||
});
|
||||
|
||||
test.beforeEach(async ({ page, skipAuth }) => {
|
||||
if (skipAuth) {
|
||||
return;
|
||||
}
|
||||
|
||||
await ensurePageAuthenticated(page);
|
||||
|
||||
let authCheckInFlight: Promise<void> | null = null;
|
||||
const maybeReauthenticate = async () => {
|
||||
if (authCheckInFlight) {
|
||||
return authCheckInFlight;
|
||||
}
|
||||
|
||||
authCheckInFlight = (async () => {
|
||||
const loginPrompt = page.getByText("Sign in to access your drawings");
|
||||
if (await loginPrompt.isVisible({ timeout: 3000 }).catch(() => false)) {
|
||||
await ensurePageAuthenticated(page, { skipNavigation: true });
|
||||
}
|
||||
})().finally(() => {
|
||||
authCheckInFlight = null;
|
||||
});
|
||||
|
||||
return authCheckInFlight;
|
||||
};
|
||||
|
||||
page.on("framenavigated", async (frame) => {
|
||||
if (frame !== page.mainFrame()) {
|
||||
return;
|
||||
}
|
||||
|
||||
await maybeReauthenticate();
|
||||
});
|
||||
|
||||
page.on("response", async (response) => {
|
||||
if (!response.url().includes("/auth/status")) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const status = (await response.json()) as { authenticated?: boolean };
|
||||
if (status && status.authenticated === false) {
|
||||
await maybeReauthenticate();
|
||||
}
|
||||
} catch {
|
||||
// Ignore parse errors to avoid flakiness.
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
export { expect };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user