添加 API 密钥测试功能

- 在设置页面新增"测试连接"按钮
- 实现 testApiKey 方法验证 Discourse API 凭据
- 添加连接测试的成功和失败消息处理
- 更新中英文国际化文案支持新功能
This commit is contained in:
wood chen 2025-03-07 07:10:02 +08:00
parent 6338c736ca
commit 502196429a
4 changed files with 106 additions and 1 deletions

View File

@ -1,4 +1,4 @@
import { PluginSettingTab, Setting, App } from 'obsidian'; import { PluginSettingTab, Setting, App, Notice, ButtonComponent } from 'obsidian';
import DiscourseSyncPlugin from './main'; import DiscourseSyncPlugin from './main';
import { t } from './i18n'; import { t } from './i18n';
@ -66,5 +66,46 @@ export class DiscourseSyncSettingsTab extends PluginSettingTab {
await this.plugin.saveSettings(); await this.plugin.saveSettings();
}), }),
); );
new Setting(containerEl)
.setName(t('TEST_API_KEY'))
.setDesc('')
.addButton((button: ButtonComponent) => {
button
.setButtonText(t('TEST_API_KEY'))
.setCta()
.onClick(async () => {
button.setButtonText(t('TESTING'));
button.setDisabled(true);
const result = await this.plugin.testApiKey();
button.setButtonText(t('TEST_API_KEY'));
button.setDisabled(false);
if (result.success) {
new Notice(result.message, 5000);
} else {
const errorEl = containerEl.createDiv('discourse-api-error');
errorEl.createEl('h3', { text: t('API_TEST_FAILED') });
const formattedMessage = typeof result.message === 'string'
? result.message
: JSON.stringify(result.message, null, 2);
errorEl.createEl('p', { text: formattedMessage });
errorEl.style.backgroundColor = 'rgba(255, 0, 0, 0.1)';
errorEl.style.border = '1px solid rgba(255, 0, 0, 0.3)';
errorEl.style.borderRadius = '5px';
errorEl.style.padding = '10px';
errorEl.style.marginTop = '10px';
setTimeout(() => {
errorEl.remove();
}, 10000);
}
});
});
} }
} }

View File

@ -6,6 +6,11 @@ export default {
'API_KEY_DESC': "API key created in '/admin/api/keys'", 'API_KEY_DESC': "API key created in '/admin/api/keys'",
'USERNAME': 'Username', 'USERNAME': 'Username',
'USERNAME_DESC': 'Your Discourse username', 'USERNAME_DESC': 'Your Discourse username',
'TEST_API_KEY': 'Test Connection',
'TESTING': 'Testing...',
'API_TEST_SUCCESS': 'Connection successful! API key is valid',
'API_TEST_FAILED': 'API key test failed',
'MISSING_CREDENTIALS': 'Please fill in Forum URL, API Key and Username first',
// Publish page // Publish page
'PUBLISH_TO_DISCOURSE': 'Publish to Discourse', 'PUBLISH_TO_DISCOURSE': 'Publish to Discourse',

View File

@ -6,6 +6,11 @@ export default {
'API_KEY_DESC': "在'/admin/api/keys'中创建的 API 密钥", 'API_KEY_DESC': "在'/admin/api/keys'中创建的 API 密钥",
'USERNAME': '用户名', 'USERNAME': '用户名',
'USERNAME_DESC': 'Discourse 用户名', 'USERNAME_DESC': 'Discourse 用户名',
'TEST_API_KEY': '测试连接',
'TESTING': '测试中...',
'API_TEST_SUCCESS': '连接成功API密钥有效',
'API_TEST_FAILED': 'API密钥测试失败',
'MISSING_CREDENTIALS': '请先填写论坛地址、API密钥和用户名',
// 发布页面 // 发布页面
'PUBLISH_TO_DISCOURSE': '发布到 Discourse', 'PUBLISH_TO_DISCOURSE': '发布到 Discourse',

View File

@ -445,6 +445,60 @@ export default class DiscourseSyncPlugin extends Plugin {
} }
} }
/**
* API密钥是否有效
* @returns
*/
async testApiKey(): Promise<{ success: boolean; message: string }> {
if (!this.settings.baseUrl || !this.settings.apiKey || !this.settings.disUser) {
return {
success: false,
message: t('MISSING_CREDENTIALS')
};
}
const url = `${this.settings.baseUrl}/users/${this.settings.disUser}.json`;
const headers = {
"Content-Type": "application/json",
"Api-Key": this.settings.apiKey,
"Api-Username": this.settings.disUser,
};
try {
const response = await requestUrl({
url: url,
method: "GET",
contentType: "application/json",
headers,
throw: false
});
if (response.status === 200) {
return {
success: true,
message: t('API_TEST_SUCCESS')
};
} else {
let errorMessage;
try {
const errorData = await response.json;
errorMessage = errorData?.errors || errorData?.error || `${t('API_TEST_FAILED')} (${response.status})`;
} catch (e) {
errorMessage = `${t('API_TEST_FAILED')} (${response.status})`;
}
return {
success: false,
message: errorMessage
};
}
} catch (error) {
return {
success: false,
message: error.message || t('UNKNOWN_ERROR')
};
}
}
registerDirMenu(menu: Menu, file: TFile) { registerDirMenu(menu: Menu, file: TFile) {
const syncDiscourse = (item: MenuItem) => { const syncDiscourse = (item: MenuItem) => {
item.setTitle(t('PUBLISH_TO_DISCOURSE')); item.setTitle(t('PUBLISH_TO_DISCOURSE'));