feat(git-provider): add userId column to git_provider table and update relationships

- Introduced a new userId column in the git_provider table to associate git providers with users.
- Updated the foreign key reference for userId to point to the users_temp table instead of the account table.
- Modified the UnauthorizedGitProvider component to include a dialog action for disconnecting repositories, enhancing user experience.
- Added a migration script to update existing git providers with the new userId values based on the organization owner.
This commit is contained in:
Mauricio Siu
2025-06-21 20:50:07 -06:00
parent a7b644e403
commit 9686848090
7 changed files with 5780 additions and 16 deletions

View File

@@ -5,6 +5,7 @@ import {
GithubIcon, GithubIcon,
GitlabIcon, GitlabIcon,
} from "@/components/icons/data-tools-icons"; } from "@/components/icons/data-tools-icons";
import { DialogAction } from "@/components/shared/dialog-action";
import { Alert, AlertDescription } from "@/components/ui/alert"; import { Alert, AlertDescription } from "@/components/ui/alert";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
@@ -85,11 +86,11 @@ export const UnauthorizedGitProvider = ({
</AlertDescription> </AlertDescription>
</Alert> </Alert>
<Card> <Card className="border-dashed border-2 border-muted-foreground/20 bg-transparent">
<CardHeader> <CardHeader>
<CardTitle className="flex items-center gap-2"> <CardTitle className="flex items-center gap-2">
{getProviderIcon(application.sourceType)} {getProviderIcon(application.sourceType)}
<span className="capitalize"> <span className="capitalize text-sm font-medium">
{application.sourceType} Repository {application.sourceType} Repository
</span> </span>
</CardTitle> </CardTitle>
@@ -121,10 +122,19 @@ export const UnauthorizedGitProvider = ({
)} )}
<div className="pt-4 border-t"> <div className="pt-4 border-t">
<Button variant="outline" onClick={onDisconnect} className="w-full"> <DialogAction
<Unlink className="size-4 mr-2" /> title="Disconnect Repository"
Disconnect Repository description="Are you sure you want to disconnect this repository?"
</Button> type="default"
onClick={async () => {
onDisconnect();
}}
>
<Button variant="secondary" className="w-full">
<Unlink className="size-4 mr-2" />
Disconnect Repository
</Button>
</DialogAction>
<p className="text-xs text-muted-foreground mt-2"> <p className="text-xs text-muted-foreground mt-2">
Disconnecting will allow you to configure a new repository with Disconnecting will allow you to configure a new repository with
your own git providers. your own git providers.

View File

@@ -0,0 +1,15 @@
ALTER TABLE "git_provider" ADD COLUMN "userId" text;--> statement-breakpoint
-- Update existing git providers to be owned by the organization owner
-- We need to get the account.user_id for the organization owner
UPDATE "git_provider"
SET "userId" = (
SELECT a.user_id
FROM "organization" o
JOIN "account" a ON o."owner_id" = a.user_id
WHERE o.id = "git_provider"."organizationId"
);--> statement-breakpoint
-- Now make the column NOT NULL since all rows should have values
ALTER TABLE "git_provider" ALTER COLUMN "userId" SET NOT NULL;--> statement-breakpoint
ALTER TABLE "git_provider" ADD CONSTRAINT "git_provider_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;

File diff suppressed because it is too large Load Diff

View File

@@ -659,6 +659,13 @@
"when": 1750397258622, "when": 1750397258622,
"tag": "0093_nice_gorilla_man", "tag": "0093_nice_gorilla_man",
"breakpoints": true "breakpoints": true
},
{
"idx": 94,
"version": "7",
"when": 1750559214977,
"tag": "0094_numerous_carmella_unuscione",
"breakpoints": true
} }
] ]
} }

View File

@@ -74,11 +74,6 @@ export const bitbucketRouter = createTRPCRouter({
getBitbucketRepositories: protectedProcedure getBitbucketRepositories: protectedProcedure
.input(apiFindOneBitbucket) .input(apiFindOneBitbucket)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
console.log({
activeOrganizationId: ctx.session.activeOrganizationId,
userId: ctx.session.userId,
bitbucketId: input.bitbucketId,
});
const bitbucketProvider = await findBitbucketById(input.bitbucketId); const bitbucketProvider = await findBitbucketById(input.bitbucketId);
if ( if (
bitbucketProvider.gitProvider.organizationId !== bitbucketProvider.gitProvider.organizationId !==

View File

@@ -21,7 +21,6 @@ export const account = pgTable("account", {
providerId: text("provider_id").notNull(), providerId: text("provider_id").notNull(),
userId: text("user_id") userId: text("user_id")
.notNull() .notNull()
.unique()
.references(() => users_temp.id, { onDelete: "cascade" }), .references(() => users_temp.id, { onDelete: "cascade" }),
accessToken: text("access_token"), accessToken: text("access_token"),
refreshToken: text("refresh_token"), refreshToken: text("refresh_token"),

View File

@@ -3,11 +3,12 @@ import { pgEnum, pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod"; import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { z } from "zod"; import { z } from "zod";
import { account, organization } from "./account"; import { organization } from "./account";
import { bitbucket } from "./bitbucket"; import { bitbucket } from "./bitbucket";
import { gitea } from "./gitea"; import { gitea } from "./gitea";
import { github } from "./github"; import { github } from "./github";
import { gitlab } from "./gitlab"; import { gitlab } from "./gitlab";
import { users_temp } from "./user";
export const gitProviderType = pgEnum("gitProviderType", [ export const gitProviderType = pgEnum("gitProviderType", [
"github", "github",
@@ -31,7 +32,7 @@ export const gitProvider = pgTable("git_provider", {
.references(() => organization.id, { onDelete: "cascade" }), .references(() => organization.id, { onDelete: "cascade" }),
userId: text("userId") userId: text("userId")
.notNull() .notNull()
.references(() => account.userId, { onDelete: "cascade" }), .references(() => users_temp.id, { onDelete: "cascade" }),
}); });
export const gitProviderRelations = relations(gitProvider, ({ one }) => ({ export const gitProviderRelations = relations(gitProvider, ({ one }) => ({
@@ -55,9 +56,9 @@ export const gitProviderRelations = relations(gitProvider, ({ one }) => ({
fields: [gitProvider.organizationId], fields: [gitProvider.organizationId],
references: [organization.id], references: [organization.id],
}), }),
account: one(account, { user: one(users_temp, {
fields: [gitProvider.userId], fields: [gitProvider.userId],
references: [account.userId], references: [users_temp.id],
}), }),
})); }));