mirror of
https://github.com/RayLabsHQ/gitea-mirror.git
synced 2026-01-27 12:50:54 +03:00
feat: enhance API config handling by adding mapping functions for UI and database structures
This commit is contained in:
134
src/lib/utils/config-mapper.ts
Normal file
134
src/lib/utils/config-mapper.ts
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
/**
|
||||||
|
* Maps between UI config structure and database schema structure
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type {
|
||||||
|
GitHubConfig,
|
||||||
|
GiteaConfig,
|
||||||
|
MirrorOptions,
|
||||||
|
AdvancedOptions,
|
||||||
|
SaveConfigApiRequest
|
||||||
|
} from "@/types/config";
|
||||||
|
|
||||||
|
interface DbGitHubConfig {
|
||||||
|
username: string;
|
||||||
|
token?: string;
|
||||||
|
skipForks: boolean;
|
||||||
|
privateRepositories: boolean;
|
||||||
|
mirrorIssues: boolean;
|
||||||
|
mirrorWiki: boolean;
|
||||||
|
mirrorStarred: boolean;
|
||||||
|
useSpecificUser: boolean;
|
||||||
|
singleRepo?: string;
|
||||||
|
includeOrgs: string[];
|
||||||
|
excludeOrgs: string[];
|
||||||
|
mirrorPublicOrgs: boolean;
|
||||||
|
publicOrgs: string[];
|
||||||
|
skipStarredIssues: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DbGiteaConfig {
|
||||||
|
username: string;
|
||||||
|
url: string;
|
||||||
|
token: string;
|
||||||
|
organization?: string;
|
||||||
|
visibility: "public" | "private" | "limited";
|
||||||
|
starredReposOrg: string;
|
||||||
|
preserveOrgStructure: boolean;
|
||||||
|
mirrorStrategy?: "preserve" | "single-org" | "flat-user";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps UI config structure to database schema structure
|
||||||
|
*/
|
||||||
|
export function mapUiToDbConfig(
|
||||||
|
githubConfig: GitHubConfig,
|
||||||
|
giteaConfig: GiteaConfig,
|
||||||
|
mirrorOptions: MirrorOptions,
|
||||||
|
advancedOptions: AdvancedOptions
|
||||||
|
): { githubConfig: DbGitHubConfig; giteaConfig: DbGiteaConfig } {
|
||||||
|
// Map GitHub config with fields from mirrorOptions and advancedOptions
|
||||||
|
const dbGithubConfig: DbGitHubConfig = {
|
||||||
|
username: githubConfig.username,
|
||||||
|
token: githubConfig.token,
|
||||||
|
privateRepositories: githubConfig.privateRepositories,
|
||||||
|
mirrorStarred: githubConfig.mirrorStarred,
|
||||||
|
|
||||||
|
// From mirrorOptions
|
||||||
|
mirrorIssues: mirrorOptions.mirrorMetadata && mirrorOptions.metadataComponents.issues,
|
||||||
|
mirrorWiki: mirrorOptions.mirrorMetadata && mirrorOptions.metadataComponents.wiki,
|
||||||
|
|
||||||
|
// From advancedOptions
|
||||||
|
skipForks: advancedOptions.skipForks,
|
||||||
|
skipStarredIssues: advancedOptions.skipStarredIssues,
|
||||||
|
|
||||||
|
// Default values for fields not in UI
|
||||||
|
useSpecificUser: false,
|
||||||
|
includeOrgs: [],
|
||||||
|
excludeOrgs: [],
|
||||||
|
mirrorPublicOrgs: false,
|
||||||
|
publicOrgs: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Gitea config remains mostly the same
|
||||||
|
const dbGiteaConfig: DbGiteaConfig = {
|
||||||
|
...giteaConfig,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
githubConfig: dbGithubConfig,
|
||||||
|
giteaConfig: dbGiteaConfig,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps database schema structure to UI config structure
|
||||||
|
*/
|
||||||
|
export function mapDbToUiConfig(dbConfig: any): {
|
||||||
|
githubConfig: GitHubConfig;
|
||||||
|
giteaConfig: GiteaConfig;
|
||||||
|
mirrorOptions: MirrorOptions;
|
||||||
|
advancedOptions: AdvancedOptions;
|
||||||
|
} {
|
||||||
|
const githubConfig: GitHubConfig = {
|
||||||
|
username: dbConfig.githubConfig?.username || "",
|
||||||
|
token: dbConfig.githubConfig?.token || "",
|
||||||
|
privateRepositories: dbConfig.githubConfig?.privateRepositories || false,
|
||||||
|
mirrorStarred: dbConfig.githubConfig?.mirrorStarred || false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const giteaConfig: GiteaConfig = {
|
||||||
|
url: dbConfig.giteaConfig?.url || "",
|
||||||
|
username: dbConfig.giteaConfig?.username || "",
|
||||||
|
token: dbConfig.giteaConfig?.token || "",
|
||||||
|
organization: dbConfig.giteaConfig?.organization || "github-mirrors",
|
||||||
|
visibility: dbConfig.giteaConfig?.visibility || "public",
|
||||||
|
starredReposOrg: dbConfig.giteaConfig?.starredReposOrg || "github",
|
||||||
|
preserveOrgStructure: dbConfig.giteaConfig?.preserveOrgStructure || false,
|
||||||
|
mirrorStrategy: dbConfig.giteaConfig?.mirrorStrategy,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mirrorOptions: MirrorOptions = {
|
||||||
|
mirrorReleases: false, // Not stored in DB yet
|
||||||
|
mirrorMetadata: dbConfig.githubConfig?.mirrorIssues || dbConfig.githubConfig?.mirrorWiki || false,
|
||||||
|
metadataComponents: {
|
||||||
|
issues: dbConfig.githubConfig?.mirrorIssues || false,
|
||||||
|
pullRequests: false, // Not stored in DB yet
|
||||||
|
labels: false, // Not stored in DB yet
|
||||||
|
milestones: false, // Not stored in DB yet
|
||||||
|
wiki: dbConfig.githubConfig?.mirrorWiki || false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const advancedOptions: AdvancedOptions = {
|
||||||
|
skipForks: dbConfig.githubConfig?.skipForks || false,
|
||||||
|
skipStarredIssues: dbConfig.githubConfig?.skipStarredIssues || false,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
githubConfig,
|
||||||
|
giteaConfig,
|
||||||
|
mirrorOptions,
|
||||||
|
advancedOptions,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -4,18 +4,19 @@ import { v4 as uuidv4 } from "uuid";
|
|||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { calculateCleanupInterval } from "@/lib/cleanup-service";
|
import { calculateCleanupInterval } from "@/lib/cleanup-service";
|
||||||
import { createSecureErrorResponse } from "@/lib/utils";
|
import { createSecureErrorResponse } from "@/lib/utils";
|
||||||
|
import { mapUiToDbConfig, mapDbToUiConfig } from "@/lib/utils/config-mapper";
|
||||||
|
|
||||||
export const POST: APIRoute = async ({ request }) => {
|
export const POST: APIRoute = async ({ request }) => {
|
||||||
try {
|
try {
|
||||||
const body = await request.json();
|
const body = await request.json();
|
||||||
const { userId, githubConfig, giteaConfig, scheduleConfig, cleanupConfig } = body;
|
const { userId, githubConfig, giteaConfig, scheduleConfig, cleanupConfig, mirrorOptions, advancedOptions } = body;
|
||||||
|
|
||||||
if (!userId || !githubConfig || !giteaConfig || !scheduleConfig || !cleanupConfig) {
|
if (!userId || !githubConfig || !giteaConfig || !scheduleConfig || !cleanupConfig || !mirrorOptions || !advancedOptions) {
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
success: false,
|
success: false,
|
||||||
message:
|
message:
|
||||||
"userId, githubConfig, giteaConfig, scheduleConfig, and cleanupConfig are required.",
|
"userId, githubConfig, giteaConfig, scheduleConfig, cleanupConfig, mirrorOptions, and advancedOptions are required.",
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
status: 400,
|
status: 400,
|
||||||
@@ -33,6 +34,14 @@ export const POST: APIRoute = async ({ request }) => {
|
|||||||
|
|
||||||
const existingConfig = existingConfigResult[0];
|
const existingConfig = existingConfigResult[0];
|
||||||
|
|
||||||
|
// Map UI structure to database schema structure first
|
||||||
|
const { githubConfig: mappedGithubConfig, giteaConfig: mappedGiteaConfig } = mapUiToDbConfig(
|
||||||
|
githubConfig,
|
||||||
|
giteaConfig,
|
||||||
|
mirrorOptions,
|
||||||
|
advancedOptions
|
||||||
|
);
|
||||||
|
|
||||||
// Preserve tokens if fields are empty
|
// Preserve tokens if fields are empty
|
||||||
if (existingConfig) {
|
if (existingConfig) {
|
||||||
try {
|
try {
|
||||||
@@ -46,12 +55,12 @@ export const POST: APIRoute = async ({ request }) => {
|
|||||||
? JSON.parse(existingConfig.giteaConfig)
|
? JSON.parse(existingConfig.giteaConfig)
|
||||||
: existingConfig.giteaConfig;
|
: existingConfig.giteaConfig;
|
||||||
|
|
||||||
if (!githubConfig.token && existingGithub.token) {
|
if (!mappedGithubConfig.token && existingGithub.token) {
|
||||||
githubConfig.token = existingGithub.token;
|
mappedGithubConfig.token = existingGithub.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!giteaConfig.token && existingGitea.token) {
|
if (!mappedGiteaConfig.token && existingGitea.token) {
|
||||||
giteaConfig.token = existingGitea.token;
|
mappedGiteaConfig.token = existingGitea.token;
|
||||||
}
|
}
|
||||||
} catch (tokenError) {
|
} catch (tokenError) {
|
||||||
console.error("Failed to preserve tokens:", tokenError);
|
console.error("Failed to preserve tokens:", tokenError);
|
||||||
@@ -120,8 +129,8 @@ export const POST: APIRoute = async ({ request }) => {
|
|||||||
await db
|
await db
|
||||||
.update(configs)
|
.update(configs)
|
||||||
.set({
|
.set({
|
||||||
githubConfig,
|
githubConfig: mappedGithubConfig,
|
||||||
giteaConfig,
|
giteaConfig: mappedGiteaConfig,
|
||||||
scheduleConfig: processedScheduleConfig,
|
scheduleConfig: processedScheduleConfig,
|
||||||
cleanupConfig: processedCleanupConfig,
|
cleanupConfig: processedCleanupConfig,
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
@@ -168,8 +177,8 @@ export const POST: APIRoute = async ({ request }) => {
|
|||||||
userId,
|
userId,
|
||||||
name: "Default Configuration",
|
name: "Default Configuration",
|
||||||
isActive: true,
|
isActive: true,
|
||||||
githubConfig,
|
githubConfig: mappedGithubConfig,
|
||||||
giteaConfig,
|
giteaConfig: mappedGiteaConfig,
|
||||||
include: [],
|
include: [],
|
||||||
exclude: [],
|
exclude: [],
|
||||||
scheduleConfig: processedScheduleConfig,
|
scheduleConfig: processedScheduleConfig,
|
||||||
@@ -214,33 +223,40 @@ export const GET: APIRoute = async ({ request }) => {
|
|||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
if (config.length === 0) {
|
if (config.length === 0) {
|
||||||
// Return a default empty configuration instead of a 404 error
|
// Return a default empty configuration with UI structure
|
||||||
|
const defaultDbConfig = {
|
||||||
|
githubConfig: {
|
||||||
|
username: "",
|
||||||
|
token: "",
|
||||||
|
skipForks: false,
|
||||||
|
privateRepositories: false,
|
||||||
|
mirrorIssues: false,
|
||||||
|
mirrorWiki: false,
|
||||||
|
mirrorStarred: false,
|
||||||
|
useSpecificUser: false,
|
||||||
|
preserveOrgStructure: false,
|
||||||
|
skipStarredIssues: false,
|
||||||
|
},
|
||||||
|
giteaConfig: {
|
||||||
|
url: "",
|
||||||
|
token: "",
|
||||||
|
username: "",
|
||||||
|
organization: "github-mirrors",
|
||||||
|
visibility: "public",
|
||||||
|
starredReposOrg: "github",
|
||||||
|
preserveOrgStructure: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const uiConfig = mapDbToUiConfig(defaultDbConfig);
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
id: null,
|
id: null,
|
||||||
userId: userId,
|
userId: userId,
|
||||||
name: "Default Configuration",
|
name: "Default Configuration",
|
||||||
isActive: true,
|
isActive: true,
|
||||||
githubConfig: {
|
...uiConfig,
|
||||||
username: "",
|
|
||||||
token: "",
|
|
||||||
skipForks: false,
|
|
||||||
privateRepositories: false,
|
|
||||||
mirrorIssues: false,
|
|
||||||
mirrorWiki: false,
|
|
||||||
mirrorStarred: true,
|
|
||||||
useSpecificUser: false,
|
|
||||||
preserveOrgStructure: true,
|
|
||||||
skipStarredIssues: false,
|
|
||||||
},
|
|
||||||
giteaConfig: {
|
|
||||||
url: "",
|
|
||||||
token: "",
|
|
||||||
username: "",
|
|
||||||
organization: "github-mirrors",
|
|
||||||
visibility: "public",
|
|
||||||
starredReposOrg: "github",
|
|
||||||
},
|
|
||||||
scheduleConfig: {
|
scheduleConfig: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
interval: 3600,
|
interval: 3600,
|
||||||
@@ -261,7 +277,14 @@ export const GET: APIRoute = async ({ request }) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Response(JSON.stringify(config[0]), {
|
// Map database structure to UI structure
|
||||||
|
const dbConfig = config[0];
|
||||||
|
const uiConfig = mapDbToUiConfig(dbConfig);
|
||||||
|
|
||||||
|
return new Response(JSON.stringify({
|
||||||
|
...dbConfig,
|
||||||
|
...uiConfig,
|
||||||
|
}), {
|
||||||
status: 200,
|
status: 200,
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user