2
0
Frank 4 сар өмнө
parent
commit
a8341e2b8b

+ 8 - 14
packages/console/app/src/context/auth.ts

@@ -1,9 +1,7 @@
 import { getRequestEvent } from "solid-js/web"
 import { and, Database, eq, inArray, sql } from "@opencode/console-core/drizzle/index.js"
-import { WorkspaceTable } from "@opencode/console-core/schema/workspace.sql.js"
 import { UserTable } from "@opencode/console-core/schema/user.sql.js"
 import { redirect } from "@solidjs/router"
-import { AccountTable } from "@opencode/console-core/schema/account.sql.js"
 import { Actor } from "@opencode/console-core/actor.js"
 
 import { createClient } from "@openauthjs/openauth/client"
@@ -54,31 +52,27 @@ export const getActor = async (workspace?: string): Promise<Actor.Info> => {
     }
     const accounts = Object.keys(auth.data.account ?? {})
     if (accounts.length) {
-      const result = await Database.use((tx) =>
+      const user = await Database.use((tx) =>
         tx
-          .select({
-            user: UserTable,
-          })
-          .from(AccountTable)
-          .innerJoin(UserTable, and(eq(UserTable.email, AccountTable.email)))
-          .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, UserTable.workspaceID))
-          .where(and(inArray(AccountTable.id, accounts), eq(WorkspaceTable.id, workspace)))
+          .select()
+          .from(UserTable)
+          .where(and(eq(UserTable.workspaceID, workspace), inArray(UserTable.accountID, accounts)))
           .limit(1)
           .execute()
           .then((x) => x[0]),
       )
-      if (result) {
+      if (user) {
         await Database.use((tx) =>
           tx
             .update(UserTable)
             .set({ timeSeen: sql`now()` })
-            .where(eq(UserTable.id, result.user.id)),
+            .where(and(eq(UserTable.workspaceID, workspace), eq(UserTable.id, user.id))),
         )
         return {
           type: "user",
           properties: {
-            userID: result.user.id,
-            workspaceID: result.user.workspaceID,
+            userID: user.id,
+            workspaceID: user.workspaceID,
           },
         }
       }

+ 1 - 1
packages/console/app/src/entry-server.tsx

@@ -9,7 +9,7 @@ export default createHandler(
           <head>
             <meta charset="utf-8" />
             <meta name="viewport" content="width=device-width, initial-scale=1" />
-            <link rel="icon" href="/favicon.svg" />
+            <link rel="icon" href="/favicon-zen.svg" />
             <meta property="og:image" content="/social-share.png" />
             <meta property="twitter:image" content="/social-share.png" />
             {assets}

+ 1 - 1
packages/console/app/src/routes/index.tsx

@@ -56,7 +56,7 @@ export default function Home() {
     <main data-page="opencode">
       <HttpHeader name="Cache-Control" value="public, max-age=1, s-maxage=3600, stale-while-revalidate=86400" />
       <Title>OpenCode | The AI coding agent built for the terminal</Title>
-      <Link rel="icon" type="image/svg+xml" href="/favicon.svg" />
+      <Link rel="icon" type="image/svg+xml" href="/favicon-zen.svg" />
       <Meta property="og:image" content="/social-share.png" />
       <Meta name="twitter:image" content="/social-share.png" />
       <div data-component="container">

+ 1 - 1
packages/console/app/src/routes/workspace.tsx

@@ -38,7 +38,7 @@ const logout = action(async () => {
       event!.locals.actor = undefined
       return val
     })
-  throw redirect("/")
+  throw redirect("/zen")
 })
 
 export default function WorkspaceLayout(props: RouteSectionProps) {

+ 2 - 2
packages/console/app/src/routes/workspace/member-section.tsx

@@ -169,7 +169,7 @@ function MemberRow(props: { member: any; workspaceID: string; currentUserID: str
       when={editing()}
       fallback={
         <tr>
-          <td data-slot="member-email">{props.member.email}</td>
+          <td data-slot="member-email">{props.member.accountEmail ?? props.member.email}</td>
           <td data-slot="member-role">{props.member.role}</td>
           <Show when={!props.member.timeSeen} fallback={<td data-slot="member-joined"></td>}>
             <td data-slot="member-joined">invited</td>
@@ -192,7 +192,7 @@ function MemberRow(props: { member: any; workspaceID: string; currentUserID: str
       <tr>
         <td colspan="4">
           <form action={updateMemberRole} method="post">
-            <div data-slot="edit-member-email">{props.member.email}</div>
+            <div data-slot="edit-member-email">{props.member.accountEmail ?? props.member.email}</div>
             <input type="hidden" name="id" value={props.member.id} />
             <input type="hidden" name="workspaceID" value={props.workspaceID} />
             <Show when={!isCurrentUser()} fallback={<div data-slot="current-user-role">Role: {props.member.role}</div>}>

+ 1 - 1
packages/console/core/src/account.ts

@@ -54,7 +54,7 @@ export namespace Account {
         .select(getTableColumns(WorkspaceTable))
         .from(WorkspaceTable)
         .innerJoin(UserTable, eq(UserTable.workspaceID, WorkspaceTable.id))
-        .where(and(eq(UserTable.email, actor.properties.email), isNull(WorkspaceTable.timeDeleted)))
+        .where(and(eq(UserTable.accountID, actor.properties.accountID), isNull(WorkspaceTable.timeDeleted)))
         .execute(),
     )
   }

+ 7 - 1
packages/console/core/src/schema/user.sql.ts

@@ -1,6 +1,7 @@
-import { mysqlTable, uniqueIndex, varchar, int, mysqlEnum } from "drizzle-orm/mysql-core"
+import { mysqlTable, uniqueIndex, varchar, int, mysqlEnum, foreignKey } from "drizzle-orm/mysql-core"
 import { timestamps, ulid, utc, workspaceColumns } from "../drizzle/types"
 import { workspaceIndexes } from "./workspace.sql"
+import { AccountTable } from "./account.sql"
 
 export const UserRole = ["admin", "member"] as const
 
@@ -22,5 +23,10 @@ export const UserTable = mysqlTable(
     ...workspaceIndexes(table),
     uniqueIndex("user_account_id").on(table.workspaceID, table.accountID),
     uniqueIndex("user_email").on(table.workspaceID, table.email),
+    foreignKey({
+      columns: [table.accountID],
+      foreignColumns: [AccountTable.id],
+      name: "global_account_id",
+    }),
   ],
 )

+ 19 - 11
packages/console/core/src/user.ts

@@ -1,5 +1,5 @@
 import { z } from "zod"
-import { and, eq, isNull, sql } from "drizzle-orm"
+import { and, eq, getTableColumns, isNull, sql } from "drizzle-orm"
 import { fn } from "./util/fn"
 import { Database } from "./drizzle"
 import { UserRole, UserTable } from "./schema/user.sql"
@@ -9,6 +9,7 @@ import { render } from "@jsx-email/render"
 import { InviteEmail } from "@opencode/console-mail/InviteEmail.jsx"
 import { AWS } from "./aws"
 import { Account } from "./account"
+import { AccountTable } from "./schema/account.sql"
 
 export namespace User {
   const assertAdmin = async () => {
@@ -29,8 +30,12 @@ export namespace User {
   export const list = fn(z.void(), () =>
     Database.use((tx) =>
       tx
-        .select()
+        .select({
+          ...getTableColumns(UserTable),
+          accountEmail: AccountTable.email,
+        })
         .from(UserTable)
+        .leftJoin(AccountTable, eq(UserTable.accountID, AccountTable.id))
         .where(and(eq(UserTable.workspaceID, Actor.workspace()), isNull(UserTable.timeDeleted))),
     ),
   )
@@ -159,19 +164,22 @@ export namespace User {
     await assertAdmin()
     assertNotSelf(id)
 
-    return await Database.use(async (tx) => {
-      const email = await tx
-        .select({ email: UserTable.email })
-        .from(UserTable)
-        .where(and(eq(UserTable.id, id), eq(UserTable.workspaceID, Actor.workspace())))
-        .then((rows) => rows[0]?.email)
-      if (!email) throw new Error("User not found")
+    return await Database.transaction(async (tx) => {
+      const user = await fromID(id)
+      if (!user) throw new Error("User not found")
 
       await tx
         .update(UserTable)
         .set({
-          oldEmail: email,
-          email: null,
+          ...(user.email
+            ? {
+                oldEmail: user.email,
+                email: null,
+              }
+            : {
+                oldAccountID: user.accountID,
+                accountID: null,
+              }),
           timeDeleted: sql`now()`,
         })
         .where(and(eq(UserTable.id, id), eq(UserTable.workspaceID, Actor.workspace())))

+ 2 - 5
packages/console/core/src/workspace.ts

@@ -1,7 +1,7 @@
 import { z } from "zod"
 import { fn } from "./util/fn"
 import { Actor } from "./actor"
-import { Database, sql } from "./drizzle"
+import { Database } from "./drizzle"
 import { Identifier } from "./identifier"
 import { UserTable } from "./schema/user.sql"
 import { BillingTable } from "./schema/billing.sql"
@@ -20,7 +20,6 @@ export namespace Workspace {
         workspaceID,
         id: Identifier.create("user"),
         accountID: account.properties.accountID,
-        email: account.properties.email,
         name: "",
         role: "admin",
       })
@@ -35,9 +34,7 @@ export namespace Workspace {
       {
         workspaceID,
       },
-      async () => {
-        await Key.create({ name: "Default API Key" })
-      },
+      () => Key.create({ name: "Default API Key" }),
     )
     return workspaceID
   })

+ 1 - 1
packages/console/function/src/auth.ts

@@ -29,7 +29,7 @@ export const subjects = createSubjects({
 
 const MY_THEME: Theme = {
   ...THEME_OPENAUTH,
-  logo: "https://opencode.ai/favicon.svg",
+  logo: "https://opencode.ai/favicon-zen.svg",
 }
 
 export default {