Skip to content

Commit e6a3151

Browse files
committed
some more fixes
1 parent 4430625 commit e6a3151

File tree

9 files changed

+291
-164
lines changed

9 files changed

+291
-164
lines changed

src/components/NotFound.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import React from "react";
21
import { Button } from "@/components/ui/button";
32
import { Card, CardContent, CardHeader } from "@/components/ui/card";
43
import { Home, ArrowLeft, GitBranch, BookOpen, Settings, FileQuestion } from "lucide-react";

src/hooks/useAuth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
114114
// Create the context value
115115
const contextValue = {
116116
user: user as AuthUser | null,
117-
session,
117+
session: session as Session | null,
118118
isLoading: isLoading || betterAuthSession.isPending,
119119
error,
120120
login,

src/lib/auth-client.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { createAuthClient } from "better-auth/react";
22
import { oidcClient } from "better-auth/client/plugins";
33
import { ssoClient } from "better-auth/client/plugins";
4+
import type { Session as BetterAuthSession, User as BetterAuthUser } from "better-auth";
45

56
export const authClient = createAuthClient({
67
// The base URL is optional when running on the same domain
@@ -23,6 +24,12 @@ export const {
2324
getSession
2425
} = authClient;
2526

26-
// Export types
27-
export type Session = Awaited<ReturnType<typeof authClient.getSession>>["data"];
28-
export type AuthUser = Session extends { user: infer U } ? U : never;
27+
// Export types - directly use the types from better-auth
28+
export type Session = BetterAuthSession & {
29+
user: BetterAuthUser & {
30+
username?: string | null;
31+
};
32+
};
33+
export type AuthUser = BetterAuthUser & {
34+
username?: string | null;
35+
};

src/lib/db/schema.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ export const giteaConfigSchema = z.object({
4747
forkStrategy: z
4848
.enum(["skip", "reference", "full-copy"])
4949
.default("reference"),
50+
// Mirror options
51+
mirrorReleases: z.boolean().default(false),
52+
mirrorMetadata: z.boolean().default(false),
53+
mirrorIssues: z.boolean().default(false),
54+
mirrorPullRequests: z.boolean().default(false),
55+
mirrorLabels: z.boolean().default(false),
56+
mirrorMilestones: z.boolean().default(false),
5057
});
5158

5259
export const scheduleConfigSchema = z.object({

src/lib/gitea.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,9 @@ export const mirrorGithubRepoToGitea = async ({
272272
throw new Error("Gitea username is required.");
273273
}
274274

275+
// Decrypt config tokens for API usage
276+
const decryptedConfig = decryptConfigTokens(config as Config);
277+
275278
// Get the correct owner based on the strategy (with organization overrides)
276279
const repoOwner = await getGiteaRepoOwnerAsync({ config, repository });
277280

@@ -347,7 +350,7 @@ export const mirrorGithubRepoToGitea = async ({
347350

348351
cloneAddress = repository.cloneUrl.replace(
349352
"https://",
350-
`https://${config.githubConfig.token}@`
353+
`https://${decryptedConfig.githubConfig.token}@`
351354
);
352355
}
353356

@@ -644,6 +647,9 @@ export async function mirrorGitHubRepoToGiteaOrg({
644647
throw new Error("Gitea config is required.");
645648
}
646649

650+
// Decrypt config tokens for API usage
651+
const decryptedConfig = decryptConfigTokens(config as Config);
652+
647653
const isExisting = await isRepoPresentInGitea({
648654
config,
649655
owner: orgName,
@@ -698,7 +704,7 @@ export async function mirrorGitHubRepoToGiteaOrg({
698704

699705
cloneAddress = repository.cloneUrl.replace(
700706
"https://",
701-
`https://${config.githubConfig.token}@`
707+
`https://${decryptedConfig.githubConfig.token}@`
702708
);
703709
}
704710

@@ -1125,7 +1131,7 @@ export const syncGiteaRepo = async ({
11251131
const apiUrl = `${config.giteaConfig.url}/api/v1/repos/${actualOwner}/${repository.name}/mirror-sync`;
11261132

11271133
const response = await httpPost(apiUrl, undefined, {
1128-
Authorization: `token ${config.giteaConfig.token}`,
1134+
Authorization: `token ${decryptedConfig.giteaConfig.token}`,
11291135
});
11301136

11311137
// Mark repo as "synced" in DB
@@ -1243,7 +1249,7 @@ export const mirrorGitRepoIssuesToGitea = async ({
12431249
const giteaLabelsRes = await httpGet(
12441250
`${config.giteaConfig.url}/api/v1/repos/${giteaOwner}/${repository.name}/labels`,
12451251
{
1246-
Authorization: `token ${config.giteaConfig.token}`,
1252+
Authorization: `token ${decryptedConfig.giteaConfig.token}`,
12471253
}
12481254
);
12491255

src/lib/utils/config-mapper.ts

Lines changed: 153 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -9,35 +9,14 @@ import type {
99
AdvancedOptions,
1010
SaveConfigApiRequest
1111
} from "@/types/config";
12+
import { z } from "zod";
13+
import { githubConfigSchema, giteaConfigSchema, scheduleConfigSchema, cleanupConfigSchema } from "@/lib/db/schema";
1214

13-
interface DbGitHubConfig {
14-
username: string;
15-
token?: string;
16-
skipForks: boolean;
17-
privateRepositories: boolean;
18-
mirrorIssues: boolean;
19-
mirrorWiki: boolean;
20-
mirrorStarred: boolean;
21-
useSpecificUser: boolean;
22-
singleRepo?: string;
23-
includeOrgs: string[];
24-
excludeOrgs: string[];
25-
mirrorPublicOrgs: boolean;
26-
publicOrgs: string[];
27-
skipStarredIssues: boolean;
28-
}
29-
30-
interface DbGiteaConfig {
31-
username: string;
32-
url: string;
33-
token: string;
34-
organization?: string;
35-
visibility: "public" | "private" | "limited";
36-
starredReposOrg: string;
37-
preserveOrgStructure: boolean;
38-
mirrorStrategy?: "preserve" | "single-org" | "flat-user" | "mixed";
39-
personalReposOrg?: string;
40-
}
15+
// Use the actual database schema types
16+
type DbGitHubConfig = z.infer<typeof githubConfigSchema>;
17+
type DbGiteaConfig = z.infer<typeof giteaConfigSchema>;
18+
type DbScheduleConfig = z.infer<typeof scheduleConfigSchema>;
19+
type DbCleanupConfig = z.infer<typeof cleanupConfigSchema>;
4120

4221
/**
4322
* Maps UI config structure to database schema structure
@@ -48,32 +27,67 @@ export function mapUiToDbConfig(
4827
mirrorOptions: MirrorOptions,
4928
advancedOptions: AdvancedOptions
5029
): { githubConfig: DbGitHubConfig; giteaConfig: DbGiteaConfig } {
51-
// Map GitHub config with fields from mirrorOptions and advancedOptions
30+
// Map GitHub config to match database schema fields
5231
const dbGithubConfig: DbGitHubConfig = {
53-
username: githubConfig.username,
54-
token: githubConfig.token,
55-
privateRepositories: githubConfig.privateRepositories,
56-
mirrorStarred: githubConfig.mirrorStarred,
32+
// Map username to owner field
33+
owner: githubConfig.username,
34+
type: "personal", // Default to personal, could be made configurable
35+
token: githubConfig.token || "",
5736

58-
// From mirrorOptions
59-
mirrorIssues: mirrorOptions.mirrorMetadata && mirrorOptions.metadataComponents.issues,
60-
mirrorWiki: mirrorOptions.mirrorMetadata && mirrorOptions.metadataComponents.wiki,
37+
// Map checkbox fields with proper names
38+
includeStarred: githubConfig.mirrorStarred,
39+
includePrivate: githubConfig.privateRepositories,
40+
includeForks: !advancedOptions.skipForks, // Note: UI has skipForks, DB has includeForks
41+
includeArchived: false, // Not in UI yet, default to false
42+
includePublic: true, // Not in UI yet, default to true
43+
44+
// Organization related fields
45+
includeOrganizations: [], // Not in UI yet
6146

62-
// From advancedOptions
63-
skipForks: advancedOptions.skipForks,
64-
skipStarredIssues: advancedOptions.skipStarredIssues,
47+
// Starred repos organization
48+
starredReposOrg: giteaConfig.starredReposOrg,
6549

66-
// Default values for fields not in UI
67-
useSpecificUser: false,
68-
includeOrgs: [],
69-
excludeOrgs: [],
70-
mirrorPublicOrgs: false,
71-
publicOrgs: [],
50+
// Mirror strategy
51+
mirrorStrategy: giteaConfig.mirrorStrategy || "preserve",
52+
defaultOrg: giteaConfig.organization,
7253
};
7354

74-
// Gitea config remains mostly the same
55+
// Map Gitea config to match database schema
7556
const dbGiteaConfig: DbGiteaConfig = {
76-
...giteaConfig,
57+
url: giteaConfig.url,
58+
token: giteaConfig.token,
59+
defaultOwner: giteaConfig.username, // Map username to defaultOwner
60+
61+
// Mirror interval and options
62+
mirrorInterval: "8h", // Default value, could be made configurable
63+
lfs: false, // Not in UI yet
64+
wiki: mirrorOptions.mirrorMetadata && mirrorOptions.metadataComponents.wiki,
65+
66+
// Visibility settings
67+
visibility: giteaConfig.visibility || "default",
68+
preserveVisibility: giteaConfig.preserveOrgStructure,
69+
70+
// Organization creation
71+
createOrg: true, // Default to true
72+
73+
// Template settings (not in UI yet)
74+
templateOwner: undefined,
75+
templateRepo: undefined,
76+
77+
// Topics
78+
addTopics: true, // Default to true
79+
topicPrefix: undefined,
80+
81+
// Fork strategy
82+
forkStrategy: advancedOptions.skipForks ? "skip" : "reference",
83+
84+
// Mirror options from UI
85+
mirrorReleases: mirrorOptions.mirrorReleases,
86+
mirrorMetadata: mirrorOptions.mirrorMetadata,
87+
mirrorIssues: mirrorOptions.mirrorMetadata && mirrorOptions.metadataComponents.issues,
88+
mirrorPullRequests: mirrorOptions.mirrorMetadata && mirrorOptions.metadataComponents.pullRequests,
89+
mirrorLabels: mirrorOptions.mirrorMetadata && mirrorOptions.metadataComponents.labels,
90+
mirrorMilestones: mirrorOptions.mirrorMetadata && mirrorOptions.metadataComponents.milestones,
7791
};
7892

7993
return {
@@ -91,40 +105,44 @@ export function mapDbToUiConfig(dbConfig: any): {
91105
mirrorOptions: MirrorOptions;
92106
advancedOptions: AdvancedOptions;
93107
} {
108+
// Map from database GitHub config to UI fields
94109
const githubConfig: GitHubConfig = {
95-
username: dbConfig.githubConfig?.username || "",
110+
username: dbConfig.githubConfig?.owner || "", // Map owner to username
96111
token: dbConfig.githubConfig?.token || "",
97-
privateRepositories: dbConfig.githubConfig?.privateRepositories || false,
98-
mirrorStarred: dbConfig.githubConfig?.mirrorStarred || false,
112+
privateRepositories: dbConfig.githubConfig?.includePrivate || false, // Map includePrivate to privateRepositories
113+
mirrorStarred: dbConfig.githubConfig?.includeStarred || false, // Map includeStarred to mirrorStarred
99114
};
100115

116+
// Map from database Gitea config to UI fields
101117
const giteaConfig: GiteaConfig = {
102118
url: dbConfig.giteaConfig?.url || "",
103-
username: dbConfig.giteaConfig?.username || "",
119+
username: dbConfig.giteaConfig?.defaultOwner || "", // Map defaultOwner to username
104120
token: dbConfig.giteaConfig?.token || "",
105-
organization: dbConfig.giteaConfig?.organization || "github-mirrors",
106-
visibility: dbConfig.giteaConfig?.visibility || "public",
107-
starredReposOrg: dbConfig.giteaConfig?.starredReposOrg || "github",
108-
preserveOrgStructure: dbConfig.giteaConfig?.preserveOrgStructure || false,
109-
mirrorStrategy: dbConfig.giteaConfig?.mirrorStrategy,
110-
personalReposOrg: dbConfig.giteaConfig?.personalReposOrg,
121+
organization: dbConfig.githubConfig?.defaultOrg || "github-mirrors", // Get from GitHub config
122+
visibility: dbConfig.giteaConfig?.visibility === "default" ? "public" : dbConfig.giteaConfig?.visibility || "public",
123+
starredReposOrg: dbConfig.githubConfig?.starredReposOrg || "github", // Get from GitHub config
124+
preserveOrgStructure: dbConfig.giteaConfig?.preserveVisibility || false, // Map preserveVisibility
125+
mirrorStrategy: dbConfig.githubConfig?.mirrorStrategy || "preserve", // Get from GitHub config
126+
personalReposOrg: undefined, // Not stored in current schema
111127
};
112128

129+
// Map mirror options from various database fields
113130
const mirrorOptions: MirrorOptions = {
114-
mirrorReleases: false, // Not stored in DB yet
115-
mirrorMetadata: dbConfig.githubConfig?.mirrorIssues || dbConfig.githubConfig?.mirrorWiki || false,
131+
mirrorReleases: dbConfig.giteaConfig?.mirrorReleases || false,
132+
mirrorMetadata: dbConfig.giteaConfig?.mirrorMetadata || false,
116133
metadataComponents: {
117-
issues: dbConfig.githubConfig?.mirrorIssues || false,
118-
pullRequests: false, // Not stored in DB yet
119-
labels: false, // Not stored in DB yet
120-
milestones: false, // Not stored in DB yet
121-
wiki: dbConfig.githubConfig?.mirrorWiki || false,
134+
issues: dbConfig.giteaConfig?.mirrorIssues || false,
135+
pullRequests: dbConfig.giteaConfig?.mirrorPullRequests || false,
136+
labels: dbConfig.giteaConfig?.mirrorLabels || false,
137+
milestones: dbConfig.giteaConfig?.mirrorMilestones || false,
138+
wiki: dbConfig.giteaConfig?.wiki || false,
122139
},
123140
};
124141

142+
// Map advanced options
125143
const advancedOptions: AdvancedOptions = {
126-
skipForks: dbConfig.githubConfig?.skipForks || false,
127-
skipStarredIssues: dbConfig.githubConfig?.skipStarredIssues || false,
144+
skipForks: !(dbConfig.githubConfig?.includeForks ?? true), // Invert includeForks to get skipForks
145+
skipStarredIssues: false, // Not stored in current schema
128146
};
129147

130148
return {
@@ -133,4 +151,73 @@ export function mapDbToUiConfig(dbConfig: any): {
133151
mirrorOptions,
134152
advancedOptions,
135153
};
154+
}
155+
156+
/**
157+
* Maps UI schedule config to database schema
158+
*/
159+
export function mapUiScheduleToDb(uiSchedule: any): DbScheduleConfig {
160+
return {
161+
enabled: uiSchedule.enabled || false,
162+
interval: uiSchedule.interval ? `0 */${Math.floor(uiSchedule.interval / 3600)} * * *` : "0 2 * * *", // Convert seconds to cron expression
163+
concurrent: false,
164+
batchSize: 10,
165+
pauseBetweenBatches: 5000,
166+
retryAttempts: 3,
167+
retryDelay: 60000,
168+
timeout: 3600000,
169+
autoRetry: true,
170+
cleanupBeforeMirror: false,
171+
notifyOnFailure: true,
172+
notifyOnSuccess: false,
173+
logLevel: "info",
174+
timezone: "UTC",
175+
onlyMirrorUpdated: false,
176+
updateInterval: 86400000,
177+
skipRecentlyMirrored: true,
178+
recentThreshold: 3600000,
179+
};
180+
}
181+
182+
/**
183+
* Maps database schedule config to UI format
184+
*/
185+
export function mapDbScheduleToUi(dbSchedule: DbScheduleConfig): any {
186+
// Extract hours from cron expression if possible
187+
let intervalSeconds = 3600; // Default 1 hour
188+
const cronMatch = dbSchedule.interval.match(/0 \*\/(\d+) \* \* \*/);
189+
if (cronMatch) {
190+
intervalSeconds = parseInt(cronMatch[1]) * 3600;
191+
}
192+
193+
return {
194+
enabled: dbSchedule.enabled,
195+
interval: intervalSeconds,
196+
};
197+
}
198+
199+
/**
200+
* Maps UI cleanup config to database schema
201+
*/
202+
export function mapUiCleanupToDb(uiCleanup: any): DbCleanupConfig {
203+
return {
204+
enabled: uiCleanup.enabled || false,
205+
deleteFromGitea: false,
206+
deleteIfNotInGitHub: true,
207+
protectedRepos: [],
208+
dryRun: true,
209+
orphanedRepoAction: "archive",
210+
batchSize: 10,
211+
pauseBetweenDeletes: 2000,
212+
};
213+
}
214+
215+
/**
216+
* Maps database cleanup config to UI format
217+
*/
218+
export function mapDbCleanupToUi(dbCleanup: DbCleanupConfig): any {
219+
return {
220+
enabled: dbCleanup.enabled,
221+
retentionDays: 604800, // 7 days in seconds (kept for compatibility)
222+
};
136223
}

0 commit comments

Comments
 (0)