Skip to content

Commit 8c9ea99

Browse files
committed
fix(#850): 修复 gitea 无法备份的问题
1 parent 5df3bae commit 8c9ea99

3 files changed

Lines changed: 44 additions & 23 deletions

File tree

src/app/core/setting/sync/gitea-sync.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,9 @@ export function GiteaSync() {
138138

139139
// 自定义 URL 变化处理
140140
async function customUrlChangeHandler(e: React.ChangeEvent<HTMLInputElement>) {
141-
const value = e.target.value
141+
let value = e.target.value
142+
// 自动移除末尾的斜杠
143+
value = value.replace(/\/+$/, '')
142144
await setGiteaCustomUrl(value)
143145
// 如果是自建实例且有 token,重新检查仓库状态
144146
if (giteaInstanceType === GiteaInstanceType.SELF_HOSTED && giteaAccessToken.trim() && value.trim()) {

src/lib/sync/gitea.ts

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,18 @@ import {
1515
GiteaFileContent
1616
} from './gitea.types';
1717

18-
// 获取 Gitea 实例的 API 基础 URL
18+
// 获取 Gitea 实例的 API 基础 URL
1919
async function getGiteaApiBaseUrl(): Promise<string> {
2020
const store = await Store.load('store.json');
2121
const instanceType = await store.get<GiteaInstanceType>('giteaInstanceType') || GiteaInstanceType.OFFICIAL;
22-
22+
2323
if (instanceType === GiteaInstanceType.SELF_HOSTED) {
24-
const customUrl = await store.get<string>('giteaCustomUrl') || '';
24+
let customUrl = await store.get<string>('giteaCustomUrl') || '';
25+
// 移除末尾的斜杠,避免双斜杠问题
26+
customUrl = customUrl.replace(/\/+$/, '');
2527
return `${customUrl}/api/v1`;
2628
}
27-
29+
2830
const instance = GITEA_INSTANCES[instanceType];
2931
return `${instance.baseUrl}/api/v1`;
3032
}
@@ -110,6 +112,7 @@ export async function uploadFile({
110112
}
111113

112114
const url = `${baseUrl}/repos/${giteaUsername}/${repo}/contents/${_path}`;
115+
// Gitea API: POST 创建新文件,PUT 更新现有文件
113116
const method = sha ? 'PUT' : 'POST';
114117

115118
const response = await fetch(url, {
@@ -153,16 +156,18 @@ export async function getFiles({ path, repo }: { path: string; repo: string }) {
153156
try {
154157
const store = await Store.load('store.json');
155158
const giteaUsername = await store.get<string>('giteaUsername');
156-
159+
157160
if (!giteaUsername) {
158-
throw new Error('用户名未配置');
161+
return null;
159162
}
160163

161164
const baseUrl = await getGiteaApiBaseUrl();
162165
const headers = await getCommonHeaders();
163166
const proxy = await getProxyConfig();
164167

165-
const url = `${baseUrl}/repos/${giteaUsername}/${repo}/contents/${path}`;
168+
// 对路径进行 URL 编码,处理特殊字符
169+
const encodedPath = path.replace(/\s/g, '_').split('/').map(encodeURIComponent).join('/');
170+
const url = `${baseUrl}/repos/${giteaUsername}/${repo}/contents/${encodedPath}`;
166171

167172
const response = await fetch(url, {
168173
method: 'GET',
@@ -172,7 +177,7 @@ export async function getFiles({ path, repo }: { path: string; repo: string }) {
172177

173178
if (response.status >= 200 && response.status < 300) {
174179
const data = await response.json();
175-
180+
176181
// 如果是单个文件,返回文件信息(包含 content)
177182
if (!Array.isArray(data)) {
178183
return {
@@ -183,7 +188,7 @@ export async function getFiles({ path, repo }: { path: string; repo: string }) {
183188
content: data.content || '', // 文件内容(base64)
184189
};
185190
}
186-
191+
187192
// 如果是目录,返回文件列表
188193
return data.map((item: GiteaDirectoryItem) => {
189194
return {
@@ -195,24 +200,17 @@ export async function getFiles({ path, repo }: { path: string; repo: string }) {
195200
})
196201
}
197202

203+
// 文件或目录不存在,返回 null
198204
if (response.status >= 400 && response.status < 500) {
199205
return null
200206
}
201207

202-
const errorData = await response.json();
203-
throw {
204-
status: response.status,
205-
message: errorData.message || '获取文件列表失败'
206-
} as GiteaError;
208+
return null;
207209

208210
} catch (error) {
209211
console.error('Gitea 获取文件列表失败:', error);
210-
toast({
211-
title: '获取文件列表失败',
212-
description: (error as GiteaError).message || '获取文件列表时发生错误',
213-
variant: 'destructive',
214-
});
215-
throw error;
212+
// 静默处理错误,返回 null
213+
return null;
216214
}
217215
}
218216

src/stores/article.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { getFiles as getGithubFiles } from '@/lib/sync/github'
22
import { GithubContent } from '@/lib/sync/github.types'
33
import { getFiles as getGiteeFiles } from '@/lib/sync/gitee'
4+
import { getFiles as getGiteaFiles } from '@/lib/sync/gitea'
45
import { getFiles as getGitlabFiles } from '@/lib/sync/gitlab'
56
import { GiteeFile } from '@/lib/sync/gitee'
7+
import { GiteaDirectoryItem } from '@/lib/sync/gitea.types'
68
import { getSyncRepoName } from '@/lib/sync/repo-utils'
79
import { autoSyncIfNeeded, hasNetworkConnection, ensureDirectoryExists } from '@/lib/sync/auto-sync'
810
import { sanitizeFilePath, hasInvalidFileNameChars } from '@/lib/sync/filename-utils'
@@ -488,6 +490,11 @@ const useArticleStore = create<NoteState>((set, get) => ({
488490
if (!gitlabAccessToken) {
489491
return
490492
}
493+
} else if (primaryBackupMethod === 'gitea') {
494+
const giteaAccessToken = await store.get<string>('giteaAccessToken')
495+
if (!giteaAccessToken) {
496+
return
497+
}
491498
}
492499

493500
// 只为根目录和本地存在的已展开文件夹加载远程文件
@@ -536,11 +543,15 @@ const useArticleStore = create<NoteState>((set, get) => ({
536543
const gitlabRepo = await getSyncRepoName('gitlab');
537544
files = await getGitlabFiles({ path, repo: gitlabRepo });
538545
break;
546+
case 'gitea':
547+
const giteaRepo = await getSyncRepoName('gitea');
548+
files = await getGiteaFiles({ path, repo: giteaRepo });
549+
break;
539550
}
540551

541552
if (files) {
542553
const dirs = get().fileTree
543-
files.forEach((file: GithubContent | GiteeFile) => {
554+
files.forEach((file: GithubContent | GiteeFile | GiteaDirectoryItem) => {
544555
// 过滤以"."开头的文件和文件夹
545556
if (file.name.startsWith('.')) {
546557
return;
@@ -641,6 +652,9 @@ const useArticleStore = create<NoteState>((set, get) => ({
641652
} else if (primaryBackupMethod === 'gitlab') {
642653
const gitlabAccessToken = await store.get<string>('gitlabAccessToken')
643654
hasCloudSync = !!gitlabAccessToken
655+
} else if (primaryBackupMethod === 'gitea') {
656+
const giteaAccessToken = await store.get<string>('giteaAccessToken')
657+
hasCloudSync = !!giteaAccessToken
644658
}
645659

646660
// 只有在配置了云同步时才设置加载状态
@@ -731,6 +745,9 @@ const useArticleStore = create<NoteState>((set, get) => ({
731745
} else if (primaryBackupMethod === 'gitlab') {
732746
const gitlabAccessToken = await store.get<string>('gitlabAccessToken')
733747
if (!gitlabAccessToken) return
748+
} else if (primaryBackupMethod === 'gitea') {
749+
const giteaAccessToken = await store.get<string>('giteaAccessToken')
750+
if (!giteaAccessToken) return
734751
}
735752

736753
try {
@@ -748,14 +765,18 @@ const useArticleStore = create<NoteState>((set, get) => ({
748765
const gitlabRepo1 = await getSyncRepoName('gitlab');
749766
files = await getGitlabFiles({ path: fullpath, repo: gitlabRepo1 });
750767
break;
768+
case 'gitea':
769+
const giteaRepo1 = await getSyncRepoName('gitea');
770+
files = await getGiteaFiles({ path: fullpath, repo: giteaRepo1 });
771+
break;
751772
}
752773

753774
if (files) {
754775
const cacheTree = get().fileTree
755776
const currentFolder = getCurrentFolder(fullpath, cacheTree)
756777

757778
if (currentFolder) {
758-
files.forEach((file: GithubContent | GiteeFile) => {
779+
files.forEach((file: GithubContent | GiteeFile | GiteaDirectoryItem) => {
759780
// 过滤以"."开头的文件和文件夹
760781
if (file.name.startsWith('.')) {
761782
return;

0 commit comments

Comments
 (0)