's'
This commit is contained in:
105
app/api/resource/check-references/route.ts
Normal file
105
app/api/resource/check-references/route.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { getFileContent } from '@/lib/github'
|
||||
import type { NavigationData } from '@/types/navigation'
|
||||
|
||||
export const runtime = 'edge'
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const { resourcePaths } = await request.json()
|
||||
|
||||
if (!Array.isArray(resourcePaths)) {
|
||||
return NextResponse.json({ error: 'Invalid resource paths' }, { status: 400 })
|
||||
}
|
||||
|
||||
// 获取导航数据
|
||||
const navigationData = await getFileContent('navsphere/content/navigation.json') as NavigationData
|
||||
|
||||
// 获取站点配置数据
|
||||
const siteData = await getFileContent('navsphere/content/site.json') as any
|
||||
|
||||
const references: Record<string, Array<{ type: string; location: string; title?: string }>> = {}
|
||||
|
||||
// 检查每个资源路径的引用
|
||||
for (const resourcePath of resourcePaths) {
|
||||
references[resourcePath] = []
|
||||
|
||||
// 检查导航数据中的引用
|
||||
if (navigationData?.navigationItems) {
|
||||
for (const navItem of navigationData.navigationItems) {
|
||||
// 检查主导航项的图标
|
||||
if (navItem.icon === resourcePath) {
|
||||
references[resourcePath].push({
|
||||
type: 'navigation',
|
||||
location: `导航项: ${navItem.title}`,
|
||||
title: navItem.title
|
||||
})
|
||||
}
|
||||
|
||||
// 检查导航项中的子项
|
||||
if (navItem.items) {
|
||||
for (const subItem of navItem.items) {
|
||||
if (subItem.icon === resourcePath) {
|
||||
references[resourcePath].push({
|
||||
type: 'navigation',
|
||||
location: `导航子项: ${navItem.title} > ${subItem.title}`,
|
||||
title: subItem.title
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查子分类
|
||||
if (navItem.subCategories) {
|
||||
for (const subCategory of navItem.subCategories) {
|
||||
if (subCategory.icon === resourcePath) {
|
||||
references[resourcePath].push({
|
||||
type: 'navigation',
|
||||
location: `导航分类: ${navItem.title} > ${subCategory.title}`,
|
||||
title: subCategory.title
|
||||
})
|
||||
}
|
||||
|
||||
// 检查子分类中的项目
|
||||
if (subCategory.items) {
|
||||
for (const item of subCategory.items) {
|
||||
if (item.icon === resourcePath) {
|
||||
references[resourcePath].push({
|
||||
type: 'navigation',
|
||||
location: `导航项: ${navItem.title} > ${subCategory.title} > ${item.title}`,
|
||||
title: item.title
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查站点配置中的引用
|
||||
if (siteData?.appearance) {
|
||||
if (siteData.appearance.logo === resourcePath) {
|
||||
references[resourcePath].push({
|
||||
type: 'site',
|
||||
location: '站点Logo',
|
||||
title: '站点Logo'
|
||||
})
|
||||
}
|
||||
|
||||
if (siteData.appearance.favicon === resourcePath) {
|
||||
references[resourcePath].push({
|
||||
type: 'site',
|
||||
location: '站点图标',
|
||||
title: '站点图标'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json({ references })
|
||||
} catch (error) {
|
||||
console.error('Failed to check resource references:', error)
|
||||
return NextResponse.json({ error: 'Failed to check resource references' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
142
app/api/resource/route.ts
Normal file
142
app/api/resource/route.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { auth } from '@/lib/auth'
|
||||
import { commitFile, getFileContent } from '@/lib/github'
|
||||
import type { ResourceMetadata } from '@/types/resource-metadata'
|
||||
|
||||
export const runtime = 'edge'
|
||||
|
||||
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const data = await getFileContent('navsphere/content/resource-metadata.json') as ResourceMetadata
|
||||
if (!data?.metadata || !Array.isArray(data.metadata)) {
|
||||
throw new Error('Invalid data structure');
|
||||
}
|
||||
return NextResponse.json(data)
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch resource metadata:', error)
|
||||
return NextResponse.json({ error: 'Failed to fetch resource metadata' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const session = await auth();
|
||||
if (!session?.user?.accessToken) {
|
||||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
const { image } = await request.json(); // Get the Base64 image
|
||||
const base64Data = image.split(",")[1]; // Extract the Base64 part
|
||||
const binaryData = Uint8Array.from(atob(base64Data), c => c.charCodeAt(0)); // Convert Base64 to binary
|
||||
|
||||
// 获取上传结果,包含路径和 commit hash
|
||||
const { path: imageUrl, commitHash } = await uploadImageToGitHub(binaryData, session.user.accessToken);
|
||||
|
||||
// Handle metadata
|
||||
const metadata = await getFileContent('navsphere/content/resource-metadata.json') as ResourceMetadata;
|
||||
metadata.metadata.unshift({
|
||||
commit: commitHash, // 使用实际的 commit hash
|
||||
hash: commitHash, // 使用相同的 hash 作为资源标识
|
||||
path: imageUrl
|
||||
});
|
||||
|
||||
await commitFile(
|
||||
'navsphere/content/resource-metadata.json',
|
||||
JSON.stringify(metadata, null, 2),
|
||||
'Update resource metadata',
|
||||
session.user.accessToken
|
||||
);
|
||||
|
||||
return NextResponse.json({ success: true, imageUrl });
|
||||
} catch (error) {
|
||||
console.error('Failed to save resource metadata:', error);
|
||||
return NextResponse.json(
|
||||
{ error: error instanceof Error ? error.message : 'Failed to save resource metadata' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to upload image to GitHub
|
||||
async function uploadImageToGitHub(binaryData: Uint8Array, token: string): Promise<{ path: string, commitHash: string }> {
|
||||
const owner = process.env.GITHUB_OWNER!;
|
||||
const repo = process.env.GITHUB_REPO!;
|
||||
const branch = process.env.GITHUB_BRANCH || 'main'
|
||||
const path = `/assets/img_${Date.now()}.png`; // Generate a unique path for the image
|
||||
const githubPath = 'public'+path;
|
||||
|
||||
// Convert Uint8Array to Base64
|
||||
const base64String = Buffer.from(binaryData).toString('base64'); // Use Buffer to convert to Base64
|
||||
const currentFileUrl = `https://api.github.com/repos/${owner}/${repo}/contents/${githubPath}?ref=${branch}`
|
||||
// Use fetch to upload the file to GitHub
|
||||
const response = await fetch(currentFileUrl, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Authorization': `token ${token}`,
|
||||
'Accept': 'application/vnd.github.v3+json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
message: `Upload ${githubPath}`,
|
||||
content: base64String, // Send only the Base64 string
|
||||
branch: branch, // Explicitly specify the branch
|
||||
}),
|
||||
});
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
console.error('Failed to upload image to GitHub:', errorData);
|
||||
throw new Error(`Failed to upload image to GitHub: ${errorData.message || 'Unknown error'}`);
|
||||
}
|
||||
|
||||
const responseData = await response.json();
|
||||
const commitHash = responseData.commit.sha; // 获取 commit hash
|
||||
|
||||
return { path, commitHash }; // Return the URL of the uploaded image
|
||||
}
|
||||
|
||||
export async function DELETE(request: Request) {
|
||||
try {
|
||||
const session = await auth();
|
||||
if (!session?.user?.accessToken) {
|
||||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
const { resourceHashes } = await request.json();
|
||||
|
||||
if (!Array.isArray(resourceHashes) || resourceHashes.length === 0) {
|
||||
return NextResponse.json({ error: 'Invalid resource hashes' }, { status: 400 });
|
||||
}
|
||||
|
||||
// 获取当前的资源元数据
|
||||
const metadata = await getFileContent('navsphere/content/resource-metadata.json') as ResourceMetadata;
|
||||
|
||||
// 过滤掉要删除的资源
|
||||
const originalCount = metadata.metadata.length;
|
||||
metadata.metadata = metadata.metadata.filter(item => !resourceHashes.includes(item.hash));
|
||||
const deletedCount = originalCount - metadata.metadata.length;
|
||||
|
||||
// 更新资源元数据文件
|
||||
await commitFile(
|
||||
'navsphere/content/resource-metadata.json',
|
||||
JSON.stringify(metadata, null, 2),
|
||||
`Delete ${deletedCount} resource(s)`,
|
||||
session.user.accessToken
|
||||
);
|
||||
|
||||
// 注意:这里只是从元数据中删除了引用,实际的图片文件仍然存在于GitHub仓库中
|
||||
// 如果需要删除实际文件,需要额外的GitHub API调用
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
deletedCount,
|
||||
message: `成功删除 ${deletedCount} 个资源`
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to delete resources:', error);
|
||||
return NextResponse.json(
|
||||
{ error: error instanceof Error ? error.message : 'Failed to delete resources' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user