Fixed auth and regained account access
This commit is contained in:
+45
-12
@@ -452,6 +452,37 @@ const ensureSchema = async () => {
|
|||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ALTER TABLE workspace_members
|
||||||
|
ADD COLUMN IF NOT EXISTS email VARCHAR(255),
|
||||||
|
ADD COLUMN IF NOT EXISTS user_id UUID REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
ADD COLUMN IF NOT EXISTS invite_email VARCHAR(255),
|
||||||
|
ADD COLUMN IF NOT EXISTS accepted_at TIMESTAMPTZ;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = 'workspace_members'
|
||||||
|
AND column_name = 'email'
|
||||||
|
) THEN
|
||||||
|
UPDATE workspace_members
|
||||||
|
SET invite_email = COALESCE(invite_email, email)
|
||||||
|
WHERE invite_email IS NULL;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
UPDATE workspace_members
|
||||||
|
SET invite_email = ''
|
||||||
|
WHERE invite_email IS NULL;
|
||||||
|
|
||||||
|
UPDATE workspace_members
|
||||||
|
SET email = invite_email
|
||||||
|
WHERE email IS NULL;
|
||||||
|
|
||||||
|
ALTER TABLE workspace_members
|
||||||
|
ALTER COLUMN invite_email SET NOT NULL;
|
||||||
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_members_workspace_email
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_members_workspace_email
|
||||||
ON workspace_members (workspace_id, invite_email);
|
ON workspace_members (workspace_id, invite_email);
|
||||||
|
|
||||||
@@ -586,7 +617,7 @@ const getWorkspaceById = async (workspaceId: number) => {
|
|||||||
|
|
||||||
const getMembershipForUser = async (userId: string, workspaceId: number) => {
|
const getMembershipForUser = async (userId: string, workspaceId: number) => {
|
||||||
const result = await pool.query<WorkspaceMemberRow>(
|
const result = await pool.query<WorkspaceMemberRow>(
|
||||||
`SELECT id, workspace_id, user_id, invite_email, name, role, accepted_at::text, created_at
|
`SELECT id, workspace_id, user_id, COALESCE(invite_email, email) AS invite_email, name, role, accepted_at::text, created_at
|
||||||
FROM workspace_members
|
FROM workspace_members
|
||||||
WHERE workspace_id = $1
|
WHERE workspace_id = $1
|
||||||
AND user_id = $2`,
|
AND user_id = $2`,
|
||||||
@@ -611,7 +642,7 @@ const listMembershipsForUser = async (userId: string) => {
|
|||||||
workspace_members.id,
|
workspace_members.id,
|
||||||
workspace_members.workspace_id,
|
workspace_members.workspace_id,
|
||||||
workspace_members.user_id,
|
workspace_members.user_id,
|
||||||
workspace_members.invite_email,
|
COALESCE(workspace_members.invite_email, workspace_members.email) AS invite_email,
|
||||||
workspace_members.name,
|
workspace_members.name,
|
||||||
workspace_members.role,
|
workspace_members.role,
|
||||||
workspace_members.accepted_at::text,
|
workspace_members.accepted_at::text,
|
||||||
@@ -691,10 +722,11 @@ const ensurePersonalWorkspaceForUser = async (user: UserRow) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await pool.query(
|
await pool.query(
|
||||||
`INSERT INTO workspace_members (workspace_id, user_id, invite_email, name, role, accepted_at)
|
`INSERT INTO workspace_members (workspace_id, user_id, email, invite_email, name, role, accepted_at)
|
||||||
VALUES ($1, $2, $3, $4, 'owner', CURRENT_TIMESTAMP)
|
VALUES ($1, $2, $3, $3, $4, 'owner', CURRENT_TIMESTAMP)
|
||||||
ON CONFLICT (workspace_id, invite_email) DO UPDATE
|
ON CONFLICT (workspace_id, invite_email) DO UPDATE
|
||||||
SET user_id = EXCLUDED.user_id,
|
SET user_id = EXCLUDED.user_id,
|
||||||
|
email = EXCLUDED.email,
|
||||||
name = EXCLUDED.name,
|
name = EXCLUDED.name,
|
||||||
role = 'owner',
|
role = 'owner',
|
||||||
accepted_at = CURRENT_TIMESTAMP`,
|
accepted_at = CURRENT_TIMESTAMP`,
|
||||||
@@ -709,7 +741,7 @@ const claimWorkspaceInvites = async (user: UserRow) => {
|
|||||||
`UPDATE workspace_members
|
`UPDATE workspace_members
|
||||||
SET user_id = $1,
|
SET user_id = $1,
|
||||||
accepted_at = CURRENT_TIMESTAMP
|
accepted_at = CURRENT_TIMESTAMP
|
||||||
WHERE LOWER(invite_email) = LOWER($2)
|
WHERE LOWER(COALESCE(invite_email, email)) = LOWER($2)
|
||||||
AND user_id IS NULL`,
|
AND user_id IS NULL`,
|
||||||
[user.id, user.email],
|
[user.id, user.email],
|
||||||
);
|
);
|
||||||
@@ -862,7 +894,7 @@ const resolveAuth = async (token: string) => {
|
|||||||
workspace_members.id AS membership_id_row,
|
workspace_members.id AS membership_id_row,
|
||||||
workspace_members.workspace_id AS membership_workspace_id,
|
workspace_members.workspace_id AS membership_workspace_id,
|
||||||
workspace_members.user_id AS membership_user_id,
|
workspace_members.user_id AS membership_user_id,
|
||||||
workspace_members.invite_email AS membership_invite_email,
|
COALESCE(workspace_members.invite_email, workspace_members.email) AS membership_invite_email,
|
||||||
workspace_members.name AS membership_name,
|
workspace_members.name AS membership_name,
|
||||||
workspace_members.role AS membership_role,
|
workspace_members.role AS membership_role,
|
||||||
workspace_members.accepted_at::text AS membership_accepted_at,
|
workspace_members.accepted_at::text AS membership_accepted_at,
|
||||||
@@ -1390,8 +1422,8 @@ app.post('/api/workspaces', requireAuth, async (req: Request, res: Response, nex
|
|||||||
);
|
);
|
||||||
|
|
||||||
await pool.query(
|
await pool.query(
|
||||||
`INSERT INTO workspace_members (workspace_id, user_id, invite_email, name, role, accepted_at)
|
`INSERT INTO workspace_members (workspace_id, user_id, email, invite_email, name, role, accepted_at)
|
||||||
VALUES ($1, $2, $3, $4, 'owner', CURRENT_TIMESTAMP)`,
|
VALUES ($1, $2, $3, $3, $4, 'owner', CURRENT_TIMESTAMP)`,
|
||||||
[workspaceId, req.auth!.user.id, req.auth!.user.email, req.auth!.user.name],
|
[workspaceId, req.auth!.user.id, req.auth!.user.email, req.auth!.user.name],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1438,7 +1470,7 @@ app.put('/api/workspace', requireAuth, requireWorkspaceRole(['owner', 'manager']
|
|||||||
app.get('/api/workspace/members', requireAuth, async (req: Request, res: Response, next: NextFunction) => {
|
app.get('/api/workspace/members', requireAuth, async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const result = await pool.query<WorkspaceMemberRow>(
|
const result = await pool.query<WorkspaceMemberRow>(
|
||||||
`SELECT id, workspace_id, user_id, invite_email, name, role, accepted_at::text, created_at
|
`SELECT id, workspace_id, user_id, COALESCE(invite_email, email) AS invite_email, name, role, accepted_at::text, created_at
|
||||||
FROM workspace_members
|
FROM workspace_members
|
||||||
WHERE workspace_id = $1
|
WHERE workspace_id = $1
|
||||||
ORDER BY created_at ASC`,
|
ORDER BY created_at ASC`,
|
||||||
@@ -1470,14 +1502,15 @@ app.post('/api/workspace/members', requireAuth, requireWorkspaceRole(['owner', '
|
|||||||
|
|
||||||
const existingUserRow = existingUser.rows[0];
|
const existingUserRow = existingUser.rows[0];
|
||||||
const result = await pool.query<WorkspaceMemberRow>(
|
const result = await pool.query<WorkspaceMemberRow>(
|
||||||
`INSERT INTO workspace_members (workspace_id, user_id, invite_email, name, role, accepted_at)
|
`INSERT INTO workspace_members (workspace_id, user_id, email, invite_email, name, role, accepted_at)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6)
|
VALUES ($1, $2, $3, $3, $4, $5, $6)
|
||||||
ON CONFLICT (workspace_id, invite_email) DO UPDATE
|
ON CONFLICT (workspace_id, invite_email) DO UPDATE
|
||||||
SET name = EXCLUDED.name,
|
SET name = EXCLUDED.name,
|
||||||
role = EXCLUDED.role,
|
role = EXCLUDED.role,
|
||||||
|
email = EXCLUDED.email,
|
||||||
user_id = COALESCE(workspace_members.user_id, EXCLUDED.user_id),
|
user_id = COALESCE(workspace_members.user_id, EXCLUDED.user_id),
|
||||||
accepted_at = COALESCE(workspace_members.accepted_at, EXCLUDED.accepted_at)
|
accepted_at = COALESCE(workspace_members.accepted_at, EXCLUDED.accepted_at)
|
||||||
RETURNING id, workspace_id, user_id, invite_email, name, role, accepted_at::text, created_at`,
|
RETURNING id, workspace_id, user_id, COALESCE(invite_email, email) AS invite_email, name, role, accepted_at::text, created_at`,
|
||||||
[
|
[
|
||||||
req.auth!.workspace.id,
|
req.auth!.workspace.id,
|
||||||
existingUserRow?.id ?? null,
|
existingUserRow?.id ?? null,
|
||||||
|
|||||||
@@ -28,6 +28,20 @@ services:
|
|||||||
POSTGRES_USER: ${POSTGRES_USER:-flockpal}
|
POSTGRES_USER: ${POSTGRES_USER:-flockpal}
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-flockpal_dev_password}
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-flockpal_dev_password}
|
||||||
FRONTEND_URL: ${FRONTEND_URL:-http://localhost:3000}
|
FRONTEND_URL: ${FRONTEND_URL:-http://localhost:3000}
|
||||||
|
BACKEND_URL: ${BACKEND_URL:-http://localhost:5000}
|
||||||
|
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}
|
||||||
|
GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}
|
||||||
|
MICROSOFT_CLIENT_ID: ${MICROSOFT_CLIENT_ID:-}
|
||||||
|
MICROSOFT_CLIENT_SECRET: ${MICROSOFT_CLIENT_SECRET:-}
|
||||||
|
APPLE_CLIENT_ID: ${APPLE_CLIENT_ID:-}
|
||||||
|
APPLE_CLIENT_SECRET: ${APPLE_CLIENT_SECRET:-}
|
||||||
|
SMTP_HOST: ${SMTP_HOST:-}
|
||||||
|
SMTP_PORT: ${SMTP_PORT:-587}
|
||||||
|
SMTP_SECURE: ${SMTP_SECURE:-false}
|
||||||
|
SMTP_USER: ${SMTP_USER:-}
|
||||||
|
SMTP_PASS: ${SMTP_PASS:-}
|
||||||
|
SMTP_FROM_EMAIL: ${SMTP_FROM_EMAIL:-}
|
||||||
|
SMTP_FROM_NAME: ${SMTP_FROM_NAME:-FlockPal}
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres:
|
postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|||||||
Reference in New Issue
Block a user