mirror of
https://github.com/RayLabsHQ/gitea-mirror.git
synced 2026-01-29 05:40:55 +03:00
🎉 Gitea Mirror: Added
This commit is contained in:
60
src/pages/api/github/organizations.ts
Normal file
60
src/pages/api/github/organizations.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import { db } from "@/lib/db";
|
||||
import { organizations } from "@/lib/db";
|
||||
import { eq, sql } from "drizzle-orm";
|
||||
import {
|
||||
membershipRoleEnum,
|
||||
type OrganizationsApiResponse,
|
||||
} from "@/types/organizations";
|
||||
import type { Organization } from "@/lib/db/schema";
|
||||
import { repoStatusEnum } from "@/types/Repository";
|
||||
import { jsonResponse } from "@/lib/utils";
|
||||
|
||||
export const GET: APIRoute = async ({ request }) => {
|
||||
const url = new URL(request.url);
|
||||
const userId = url.searchParams.get("userId");
|
||||
|
||||
if (!userId) {
|
||||
return jsonResponse({
|
||||
data: {
|
||||
success: false,
|
||||
error: "Missing userId",
|
||||
},
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const rawOrgs = await db
|
||||
.select()
|
||||
.from(organizations)
|
||||
.where(eq(organizations.userId, userId))
|
||||
.orderBy(sql`name COLLATE NOCASE`);
|
||||
|
||||
const orgsWithIds: Organization[] = rawOrgs.map((org) => ({
|
||||
...org,
|
||||
status: repoStatusEnum.parse(org.status),
|
||||
membershipRole: membershipRoleEnum.parse(org.membershipRole),
|
||||
lastMirrored: org.lastMirrored ?? undefined,
|
||||
errorMessage: org.errorMessage ?? undefined,
|
||||
}));
|
||||
|
||||
const resPayload: OrganizationsApiResponse = {
|
||||
success: true,
|
||||
message: "Organizations fetched successfully",
|
||||
organizations: orgsWithIds,
|
||||
};
|
||||
|
||||
return jsonResponse({ data: resPayload, status: 200 });
|
||||
} catch (error) {
|
||||
console.error("Error fetching organizations:", error);
|
||||
|
||||
return jsonResponse({
|
||||
data: {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "Something went wrong",
|
||||
},
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
};
|
||||
96
src/pages/api/github/repositories.ts
Normal file
96
src/pages/api/github/repositories.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import { db, repositories, configs } from "@/lib/db";
|
||||
import { and, eq, sql } from "drizzle-orm";
|
||||
import {
|
||||
repositoryVisibilityEnum,
|
||||
repoStatusEnum,
|
||||
type RepositoryApiResponse,
|
||||
} from "@/types/Repository";
|
||||
import { jsonResponse } from "@/lib/utils";
|
||||
|
||||
export const GET: APIRoute = async ({ request }) => {
|
||||
const url = new URL(request.url);
|
||||
const userId = url.searchParams.get("userId");
|
||||
|
||||
if (!userId) {
|
||||
return jsonResponse({
|
||||
data: { success: false, error: "Missing userId" },
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
// Fetch the user's active configuration
|
||||
const [config] = await db
|
||||
.select()
|
||||
.from(configs)
|
||||
.where(and(eq(configs.userId, userId), eq(configs.isActive, true)));
|
||||
|
||||
if (!config) {
|
||||
return jsonResponse({
|
||||
data: {
|
||||
success: false,
|
||||
error: "No active configuration found for this user",
|
||||
},
|
||||
status: 404,
|
||||
});
|
||||
}
|
||||
|
||||
const githubConfig = config.githubConfig as {
|
||||
mirrorStarred: boolean;
|
||||
skipForks: boolean;
|
||||
privateRepositories: boolean;
|
||||
};
|
||||
|
||||
// Build query conditions based on config
|
||||
const conditions = [eq(repositories.userId, userId)];
|
||||
|
||||
if (!githubConfig.mirrorStarred) {
|
||||
conditions.push(eq(repositories.isStarred, false));
|
||||
}
|
||||
|
||||
if (githubConfig.skipForks) {
|
||||
conditions.push(eq(repositories.isForked, false));
|
||||
}
|
||||
|
||||
if (!githubConfig.privateRepositories) {
|
||||
conditions.push(eq(repositories.isPrivate, false));
|
||||
}
|
||||
|
||||
const rawRepositories = await db
|
||||
.select()
|
||||
.from(repositories)
|
||||
.where(and(...conditions))
|
||||
.orderBy(sql`name COLLATE NOCASE`);
|
||||
|
||||
const response: RepositoryApiResponse = {
|
||||
success: true,
|
||||
message: "Repositories fetched successfully",
|
||||
repositories: rawRepositories.map((repo) => ({
|
||||
...repo,
|
||||
organization: repo.organization ?? undefined,
|
||||
lastMirrored: repo.lastMirrored ?? undefined,
|
||||
errorMessage: repo.errorMessage ?? undefined,
|
||||
forkedFrom: repo.forkedFrom ?? undefined,
|
||||
status: repoStatusEnum.parse(repo.status),
|
||||
visibility: repositoryVisibilityEnum.parse(repo.visibility),
|
||||
})),
|
||||
};
|
||||
|
||||
return jsonResponse({
|
||||
data: response,
|
||||
status: 200,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error fetching repositories:", error);
|
||||
|
||||
return jsonResponse({
|
||||
data: {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "Something went wrong",
|
||||
message: "An error occurred while fetching repositories.",
|
||||
},
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
};
|
||||
101
src/pages/api/github/test-connection.ts
Normal file
101
src/pages/api/github/test-connection.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import { Octokit } from "@octokit/rest";
|
||||
|
||||
export const POST: APIRoute = async ({ request }) => {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { token, username } = body;
|
||||
|
||||
if (!token) {
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "GitHub token is required",
|
||||
}),
|
||||
{
|
||||
status: 400,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Create an Octokit instance with the provided token
|
||||
const octokit = new Octokit({
|
||||
auth: token,
|
||||
});
|
||||
|
||||
// Test the connection by fetching the authenticated user
|
||||
const { data } = await octokit.users.getAuthenticated();
|
||||
|
||||
// Verify that the authenticated user matches the provided username (if provided)
|
||||
if (username && data.login !== username) {
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: `Token belongs to ${data.login}, not ${username}`,
|
||||
}),
|
||||
{
|
||||
status: 400,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Return success response with user data
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
message: `Successfully connected to GitHub as ${data.login}`,
|
||||
user: {
|
||||
login: data.login,
|
||||
name: data.name,
|
||||
avatar_url: data.avatar_url,
|
||||
},
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("GitHub connection test failed:", error);
|
||||
|
||||
// Handle specific error types
|
||||
if (error instanceof Error && (error as any).status === 401) {
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "Invalid GitHub token",
|
||||
}),
|
||||
{
|
||||
status: 401,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Generic error response
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: `GitHub connection test failed: ${
|
||||
error instanceof Error ? error.message : "Unknown error"
|
||||
}`,
|
||||
}),
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user