mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
Fetch organization info in the extension (#4751)
This commit is contained in:
parent
2e2f83be60
commit
322a15ee5d
5 changed files with 149 additions and 1 deletions
|
|
@ -5,7 +5,7 @@ import axios from "axios"
|
|||
import * as vscode from "vscode"
|
||||
import { z } from "zod"
|
||||
|
||||
import type { CloudUserInfo } from "@roo-code/types"
|
||||
import type { CloudUserInfo, CloudOrganizationMembership } from "@roo-code/types"
|
||||
|
||||
import { getClerkBaseUrl, getRooCodeApiUrl } from "./Config"
|
||||
import { RefreshTimer } from "./RefreshTimer"
|
||||
|
|
@ -420,9 +420,42 @@ export class AuthService extends EventEmitter<AuthServiceEvents> {
|
|||
}
|
||||
|
||||
userInfo.picture = userData?.image_url
|
||||
|
||||
// Fetch organization memberships separately
|
||||
try {
|
||||
const orgMemberships = await this.clerkGetOrganizationMemberships()
|
||||
if (orgMemberships && orgMemberships.length > 0) {
|
||||
// Get the first (or active) organization membership
|
||||
const primaryOrgMembership = orgMemberships[0]
|
||||
const organization = primaryOrgMembership?.organization
|
||||
|
||||
if (organization) {
|
||||
userInfo.organizationId = organization.id
|
||||
userInfo.organizationName = organization.name
|
||||
userInfo.organizationRole = primaryOrgMembership.role
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.log("[auth] Failed to fetch organization memberships:", error)
|
||||
// Don't throw - organization info is optional
|
||||
}
|
||||
|
||||
return userInfo
|
||||
}
|
||||
|
||||
private async clerkGetOrganizationMemberships(): Promise<CloudOrganizationMembership[]> {
|
||||
const response = await axios.get(`${getClerkBaseUrl()}/v1/me/organization_memberships`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${this.credentials!.clientToken}`,
|
||||
"User-Agent": this.userAgent(),
|
||||
},
|
||||
})
|
||||
|
||||
// The response structure is: { response: [...] }
|
||||
// Extract the organization memberships from the response.response array
|
||||
return response.data?.response || []
|
||||
}
|
||||
|
||||
private async clerkLogout(credentials: AuthCredentials): Promise<void> {
|
||||
const formData = new URLSearchParams()
|
||||
formData.append("_is_native", "1")
|
||||
|
|
|
|||
|
|
@ -92,6 +92,24 @@ export class CloudService {
|
|||
return this.authService!.getUserInfo()
|
||||
}
|
||||
|
||||
public getOrganizationId(): string | null {
|
||||
this.ensureInitialized()
|
||||
const userInfo = this.authService!.getUserInfo()
|
||||
return userInfo?.organizationId || null
|
||||
}
|
||||
|
||||
public getOrganizationName(): string | null {
|
||||
this.ensureInitialized()
|
||||
const userInfo = this.authService!.getUserInfo()
|
||||
return userInfo?.organizationName || null
|
||||
}
|
||||
|
||||
public getOrganizationRole(): string | null {
|
||||
this.ensureInitialized()
|
||||
const userInfo = this.authService!.getUserInfo()
|
||||
return userInfo?.organizationRole || null
|
||||
}
|
||||
|
||||
public getAuthState(): string {
|
||||
this.ensureInitialized()
|
||||
return this.authService!.getState()
|
||||
|
|
|
|||
|
|
@ -184,6 +184,72 @@ describe("CloudService", () => {
|
|||
expect(mockAuthService.getUserInfo).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("should return organization ID from user info", () => {
|
||||
const mockUserInfo = {
|
||||
name: "Test User",
|
||||
email: "test@example.com",
|
||||
organizationId: "org_123",
|
||||
organizationName: "Test Org",
|
||||
organizationRole: "admin",
|
||||
}
|
||||
mockAuthService.getUserInfo.mockReturnValue(mockUserInfo)
|
||||
|
||||
const result = cloudService.getOrganizationId()
|
||||
expect(mockAuthService.getUserInfo).toHaveBeenCalled()
|
||||
expect(result).toBe("org_123")
|
||||
})
|
||||
|
||||
it("should return null when no organization ID available", () => {
|
||||
mockAuthService.getUserInfo.mockReturnValue(null)
|
||||
|
||||
const result = cloudService.getOrganizationId()
|
||||
expect(result).toBe(null)
|
||||
})
|
||||
|
||||
it("should return organization name from user info", () => {
|
||||
const mockUserInfo = {
|
||||
name: "Test User",
|
||||
email: "test@example.com",
|
||||
organizationId: "org_123",
|
||||
organizationName: "Test Org",
|
||||
organizationRole: "admin",
|
||||
}
|
||||
mockAuthService.getUserInfo.mockReturnValue(mockUserInfo)
|
||||
|
||||
const result = cloudService.getOrganizationName()
|
||||
expect(mockAuthService.getUserInfo).toHaveBeenCalled()
|
||||
expect(result).toBe("Test Org")
|
||||
})
|
||||
|
||||
it("should return null when no organization name available", () => {
|
||||
mockAuthService.getUserInfo.mockReturnValue(null)
|
||||
|
||||
const result = cloudService.getOrganizationName()
|
||||
expect(result).toBe(null)
|
||||
})
|
||||
|
||||
it("should return organization role from user info", () => {
|
||||
const mockUserInfo = {
|
||||
name: "Test User",
|
||||
email: "test@example.com",
|
||||
organizationId: "org_123",
|
||||
organizationName: "Test Org",
|
||||
organizationRole: "admin",
|
||||
}
|
||||
mockAuthService.getUserInfo.mockReturnValue(mockUserInfo)
|
||||
|
||||
const result = cloudService.getOrganizationRole()
|
||||
expect(mockAuthService.getUserInfo).toHaveBeenCalled()
|
||||
expect(result).toBe("admin")
|
||||
})
|
||||
|
||||
it("should return null when no organization role available", () => {
|
||||
mockAuthService.getUserInfo.mockReturnValue(null)
|
||||
|
||||
const result = cloudService.getOrganizationRole()
|
||||
expect(result).toBe(null)
|
||||
})
|
||||
|
||||
it("should delegate getAuthState to AuthService", () => {
|
||||
const result = cloudService.getAuthState()
|
||||
expect(mockAuthService.getState).toHaveBeenCalled()
|
||||
|
|
|
|||
|
|
@ -10,6 +10,32 @@ export interface CloudUserInfo {
|
|||
name?: string
|
||||
email?: string
|
||||
picture?: string
|
||||
organizationId?: string
|
||||
organizationName?: string
|
||||
organizationRole?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* CloudOrganization Types
|
||||
*/
|
||||
|
||||
export interface CloudOrganization {
|
||||
id: string
|
||||
name: string
|
||||
slug?: string
|
||||
image_url?: string
|
||||
has_image?: boolean
|
||||
created_at?: number
|
||||
updated_at?: number
|
||||
}
|
||||
|
||||
export interface CloudOrganizationMembership {
|
||||
id: string
|
||||
organization: CloudOrganization
|
||||
role: string
|
||||
permissions?: string[]
|
||||
created_at?: number
|
||||
updated_at?: number
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -44,6 +44,11 @@ export const AccountView = ({ userInfo, isAuthenticated, onDone }: AccountViewPr
|
|||
<h2 className="text-lg font-medium text-vscode-foreground mb-1">
|
||||
{userInfo?.name || t("account:unknownUser")}
|
||||
</h2>
|
||||
{userInfo?.organizationName && (
|
||||
<p className="text-sm text-vscode-descriptionForeground mb-1">
|
||||
{userInfo.organizationName}
|
||||
</p>
|
||||
)}
|
||||
<p className="text-sm text-vscode-descriptionForeground">{userInfo?.email || ""}</p>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue