Fixed compose bug and formatted. Updated the refresh token to check the expired time.

This commit is contained in:
Jason Parks 2025-03-27 15:27:53 -06:00
parent 5927c7c3c5
commit 66d6cb5710
7 changed files with 127 additions and 73 deletions

View File

@ -1,7 +1,7 @@
import { describe, expect, it } from "vitest"; import type { Schema } from "@dokploy/server/templates";
import type { CompleteTemplate } from "@dokploy/server/templates/processors"; import type { CompleteTemplate } from "@dokploy/server/templates/processors";
import { processTemplate } from "@dokploy/server/templates/processors"; import { processTemplate } from "@dokploy/server/templates/processors";
import type { Schema } from "@dokploy/server/templates"; import { describe, expect, it } from "vitest";
describe("processTemplate", () => { describe("processTemplate", () => {
// Mock schema for testing // Mock schema for testing

View File

@ -71,7 +71,6 @@ interface Props {
export const SaveGiteaProviderCompose = ({ composeId }: Props) => { export const SaveGiteaProviderCompose = ({ composeId }: Props) => {
const { data: giteaProviders } = api.gitea.giteaProviders.useQuery(); const { data: giteaProviders } = api.gitea.giteaProviders.useQuery();
const { data, refetch } = api.compose.one.useQuery({ composeId }); const { data, refetch } = api.compose.one.useQuery({ composeId });
const { mutateAsync, isLoading: isSavingGiteaProvider } = const { mutateAsync, isLoading: isSavingGiteaProvider } =
api.compose.update.useMutation(); api.compose.update.useMutation();
@ -97,11 +96,9 @@ export const SaveGiteaProviderCompose = ({ composeId }: Props) => {
{ giteaId }, { giteaId },
{ {
enabled: !!giteaId, enabled: !!giteaId,
} },
); );
console.log(repository);
const { const {
data: repositories, data: repositories,
isLoading: isLoadingRepositories, isLoading: isLoadingRepositories,
@ -133,24 +130,55 @@ export const SaveGiteaProviderCompose = ({ composeId }: Props) => {
useEffect(() => { useEffect(() => {
if (data) { if (data) {
// Find the repository in the repositories list to get the correct ID console.log("Setting form data from API:", data);
const currentRepo = repositories?.find(
(repo) => repo.name === data.giteaRepository && repo.owner.username === data.giteaOwner
);
form.reset({ // Only reset form on initial load, not after user interactions
branch: data.giteaBranch || "", if (!form.formState.isDirty && !form.formState.dirtyFields.giteaId) {
repository: { console.log("Initial form reset from API data");
repo: data.giteaRepository || "", form.reset({
owner: data.giteaOwner || "", branch: data.giteaBranch || "",
id: currentRepo?.id || null, repository: {
}, repo: data.giteaRepository || "",
composePath: data.composePath, owner: data.giteaOwner || "",
giteaId: data.giteaId || "", id: null,
watchPaths: data.watchPaths || [], },
}); composePath: data.composePath || "./docker-compose.yml",
giteaId: data.giteaId || "",
watchPaths: data.watchPaths || [],
});
} else {
console.log(
"Skipping form reset because form has been modified by user",
);
}
} }
}, [data, form, repositories]); }, [data]);
// Add this separate effect to update repository ID if needed
useEffect(() => {
const values = form.getValues();
// If we have a repository selected but no ID, try to find it
if (
values.repository.owner &&
values.repository.repo &&
!values.repository.id &&
repositories?.length
) {
const matchingRepo = repositories.find(
(repo) =>
repo.name === values.repository.repo &&
repo.owner.username === values.repository.owner,
);
if (matchingRepo) {
console.log("Found matching repository ID:", matchingRepo.id);
form.setValue("repository", {
...values.repository,
id: matchingRepo.id,
});
}
}
}, [repositories]);
const onSubmit = async (data: GiteaProvider) => { const onSubmit = async (data: GiteaProvider) => {
await mutateAsync({ await mutateAsync({
@ -165,7 +193,7 @@ export const SaveGiteaProviderCompose = ({ composeId }: Props) => {
watchPaths: data.watchPaths, watchPaths: data.watchPaths,
} as any) } as any)
.then(async () => { .then(async () => {
toast.success("Service Provided Saved"); toast.success("Service Provider Saved");
await refetch(); await refetch();
}) })
.catch(() => { .catch(() => {
@ -191,14 +219,20 @@ export const SaveGiteaProviderCompose = ({ composeId }: Props) => {
<FormLabel>Gitea Account</FormLabel> <FormLabel>Gitea Account</FormLabel>
<Select <Select
onValueChange={(value) => { onValueChange={(value) => {
console.log("Select changed to:", value);
field.onChange(value); field.onChange(value);
form.setValue("repository", { form.setValue(
owner: "", "repository",
repo: "", {
id: null, owner: "",
}); repo: "",
form.setValue("branch", ""); id: null,
},
{ shouldValidate: false },
);
form.setValue("branch", "", { shouldValidate: false });
}} }}
defaultValue={field.value}
value={field.value} value={field.value}
> >
<FormControl> <FormControl>
@ -281,6 +315,10 @@ export const SaveGiteaProviderCompose = ({ composeId }: Props) => {
key={repo.url} key={repo.url}
value={repo.name} value={repo.name}
onSelect={() => { onSelect={() => {
console.log(
"Repository selected:",
repo.name,
);
form.setValue("repository", { form.setValue("repository", {
owner: repo.owner.username, owner: repo.owner.username,
repo: repo.name, repo: repo.name,

View File

@ -89,18 +89,19 @@ export const ShowConvertedCompose = ({ composeId }: Props) => {
</div> </div>
{compose !== null ? ( {compose !== null ? (
<pre> <pre>
<CodeEditor <CodeEditor
value={compose || ""} value={compose || ""}
language="yaml" language="yaml"
readOnly readOnly
height="50rem" height="50rem"
/> />
</pre> </pre>
) : ( ) : (
<div className="py-4 text-center text-muted-foreground"> <div className="py-4 text-center text-muted-foreground">
No compose file available. Make sure at least one domain is configured for this project. No compose file available. Make sure at least one domain is
</div> configured for this project.
</div>
)} )}
</DialogContent> </DialogContent>
</Dialog> </Dialog>

View File

@ -220,27 +220,27 @@ export const giteaRouter = createTRPCRouter({
getGiteaUrl: protectedProcedure getGiteaUrl: protectedProcedure
.input(apiFindOneGitea) .input(apiFindOneGitea)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const { giteaId } = input; const { giteaId } = input;
if (!giteaId) { if (!giteaId) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
message: "Gitea provider ID is required.", message: "Gitea provider ID is required.",
}); });
} }
const giteaProvider = await findGiteaById(giteaId); const giteaProvider = await findGiteaById(giteaId);
if ( if (
giteaProvider.gitProvider.organizationId !== giteaProvider.gitProvider.organizationId !==
ctx.session.activeOrganizationId ctx.session.activeOrganizationId
) { ) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "You are not allowed to access this Gitea provider", message: "You are not allowed to access this Gitea provider",
}); });
} }
// Return the base URL of the Gitea instance // Return the base URL of the Gitea instance
return giteaProvider.giteaUrl; return giteaProvider.giteaUrl;
}), }),
}); });

View File

@ -2,16 +2,16 @@ import type { IncomingMessage } from "node:http";
import * as bcrypt from "bcrypt"; import * as bcrypt from "bcrypt";
import { betterAuth } from "better-auth"; import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { organization, twoFactor, apiKey } from "better-auth/plugins"; import { APIError } from "better-auth/api";
import { apiKey, organization, twoFactor } from "better-auth/plugins";
import { and, desc, eq } from "drizzle-orm"; import { and, desc, eq } from "drizzle-orm";
import { IS_CLOUD } from "../constants";
import { db } from "../db"; import { db } from "../db";
import * as schema from "../db/schema"; import * as schema from "../db/schema";
import { sendEmail } from "../verification/send-verification-email";
import { IS_CLOUD } from "../constants";
import { getPublicIpWithFallback } from "../wss/utils";
import { updateUser } from "../services/user";
import { getUserByToken } from "../services/admin"; import { getUserByToken } from "../services/admin";
import { APIError } from "better-auth/api"; import { updateUser } from "../services/user";
import { sendEmail } from "../verification/send-verification-email";
import { getPublicIpWithFallback } from "../wss/utils";
const { handler, api } = betterAuth({ const { handler, api } = betterAuth({
database: drizzleAdapter(db, { database: drizzleAdapter(db, {

View File

@ -19,8 +19,7 @@ export const getErrorCloneRequirements = (entity: {
giteaBranch?: string | null; giteaBranch?: string | null;
}) => { }) => {
const reasons: string[] = []; const reasons: string[] = [];
const { giteaBranch, giteaOwner, giteaRepository } = const { giteaBranch, giteaOwner, giteaRepository } = entity;
entity;
if (!giteaRepository) reasons.push("1. Repository not assigned."); if (!giteaRepository) reasons.push("1. Repository not assigned.");
if (!giteaOwner) reasons.push("2. Owner not specified."); if (!giteaOwner) reasons.push("2. Owner not specified.");
@ -41,6 +40,20 @@ export const refreshGiteaToken = async (giteaProviderId: string) => {
return giteaProvider?.accessToken || null; return giteaProvider?.accessToken || null;
} }
// Check if token is still valid (add some buffer time, e.g., 5 minutes)
const currentTimeSeconds = Math.floor(Date.now() / 1000);
const bufferTimeSeconds = 300; // 5 minutes
if (
giteaProvider.expiresAt &&
giteaProvider.expiresAt > currentTimeSeconds + bufferTimeSeconds &&
giteaProvider.accessToken
) {
// Token is still valid, no need to refresh
return giteaProvider.accessToken;
}
// Token is expired or about to expire, refresh it
const tokenEndpoint = `${giteaProvider.giteaUrl}/login/oauth/access_token`; const tokenEndpoint = `${giteaProvider.giteaUrl}/login/oauth/access_token`;
const params = new URLSearchParams({ const params = new URLSearchParams({
grant_type: "refresh_token", grant_type: "refresh_token",
@ -409,6 +422,8 @@ export const getGiteaBranches = async (input: {
return []; return [];
} }
await refreshGiteaToken(input.giteaId);
const giteaProvider = await findGiteaById(input.giteaId); const giteaProvider = await findGiteaById(input.giteaId);
const baseUrl = giteaProvider.giteaUrl.replace(/\/+$/, ""); const baseUrl = giteaProvider.giteaUrl.replace(/\/+$/, "");