适配ClassworksKV
This commit is contained in:
+8
-40
@@ -7,18 +7,19 @@ const isValidProvider = () => {
|
||||
return provider === "kv-server" || provider === "classworkscloud";
|
||||
};
|
||||
|
||||
// Helper function to get request headers with site key and namespace password
|
||||
// Helper function to get request headers with kvtoken
|
||||
const getHeaders = () => {
|
||||
const headers = { Accept: "application/json" };
|
||||
const kvToken = getSetting("server.kvToken");
|
||||
const siteKey = getSetting("server.siteKey");
|
||||
const namespacePassword = getSetting("namespace.password");
|
||||
|
||||
if (siteKey) {
|
||||
// 优先使用新的kvToken
|
||||
if (kvToken) {
|
||||
headers["x-app-token"] = kvToken;
|
||||
} else if (siteKey) {
|
||||
// 向后兼容旧的siteKey
|
||||
headers["x-site-key"] = siteKey;
|
||||
}
|
||||
if (namespacePassword) {
|
||||
headers["x-namespace-password"] = namespacePassword;
|
||||
}
|
||||
|
||||
return headers;
|
||||
};
|
||||
@@ -33,10 +34,9 @@ export const getNamespaceInfo = async () => {
|
||||
}
|
||||
|
||||
const serverUrl = getSetting("server.domain");
|
||||
const machineId = getSetting("device.uuid");
|
||||
|
||||
try {
|
||||
const response = await axios.get(`${serverUrl}/${machineId}/_info`, {
|
||||
const response = await axios.get(`${serverUrl}/kv/_info`, {
|
||||
headers: getHeaders(),
|
||||
});
|
||||
|
||||
@@ -44,36 +44,4 @@ export const getNamespaceInfo = async () => {
|
||||
} catch (error) {
|
||||
throw new Error(error.response?.data?.message || "获取命名空间信息失败");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update namespace password
|
||||
* @param {string} oldPassword - Current password (if exists)
|
||||
* @param {string} newPassword - New password to set
|
||||
* @returns {Promise<Object>} Response data
|
||||
*/
|
||||
export const updateNamespacePassword = async (oldPassword, newPassword) => {
|
||||
if (!isValidProvider()) {
|
||||
throw new Error("当前数据提供者不支持此操作");
|
||||
}
|
||||
|
||||
const serverUrl = getSetting("server.domain");
|
||||
const machineId = getSetting("device.uuid");
|
||||
|
||||
try {
|
||||
const response = await axios.put(
|
||||
`${serverUrl}/${machineId}/_infopassword`,
|
||||
{
|
||||
oldPassword,
|
||||
newPassword,
|
||||
},
|
||||
{
|
||||
headers: getHeaders(),
|
||||
}
|
||||
);
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw new Error(error.response?.data?.message || "更新命名空间密码失败");
|
||||
}
|
||||
};
|
||||
@@ -1,19 +1,20 @@
|
||||
import axios from "@/axios/axios";
|
||||
import { formatResponse, formatError } from "../dataProvider";
|
||||
import { getSetting, setSetting } from "../settings";
|
||||
import { getSetting } from "../settings";
|
||||
|
||||
// Helper function to get request headers with site key and password if available
|
||||
// Helper function to get request headers with kvtoken
|
||||
const getHeaders = () => {
|
||||
const headers = { Accept: "application/json" };
|
||||
const kvToken = getSetting("server.kvToken");
|
||||
const siteKey = getSetting("server.siteKey");
|
||||
const password = getSetting("namespace.password");
|
||||
|
||||
if (siteKey) {
|
||||
// 优先使用新的kvToken
|
||||
if (kvToken) {
|
||||
headers["x-app-token"] = kvToken;
|
||||
} else if (siteKey) {
|
||||
// 向后兼容旧的siteKey
|
||||
headers["x-site-key"] = siteKey;
|
||||
}
|
||||
if (password) {
|
||||
headers["x-namespace-password"] = password;
|
||||
}
|
||||
|
||||
return headers;
|
||||
};
|
||||
@@ -21,30 +22,18 @@ const getHeaders = () => {
|
||||
export const kvServerProvider = {
|
||||
async loadNamespaceInfo() {
|
||||
try {
|
||||
// 使用 Classworks Cloud 或者用户配置的服务器域名
|
||||
const provider = getSetting("server.provider");
|
||||
const serverUrl = getSetting("server.domain");
|
||||
const machineId = getSetting("device.uuid");
|
||||
|
||||
const res = await axios.get(`${serverUrl}/${machineId}/_info`, {
|
||||
const res = await axios.get(`${serverUrl}/kv/_info`, {
|
||||
headers: getHeaders(),
|
||||
});
|
||||
|
||||
const { name, accessType } = res.data;
|
||||
|
||||
// 如果name为null,使用班级号作为名称并更新
|
||||
if (name === null) {
|
||||
const classNumber = getSetting("server.classNumber");
|
||||
await this.updateNamespaceInfo({ name: classNumber });
|
||||
// 重新加载命名空间信息
|
||||
return await this.loadNamespaceInfo();
|
||||
}
|
||||
|
||||
// 更新本地访问权限设置
|
||||
if (accessType) {
|
||||
setSetting("namespace.accessType", accessType);
|
||||
}
|
||||
|
||||
return formatResponse(res);
|
||||
// 直接返回新格式 API 数据,包含 device 和 account 信息
|
||||
return formatResponse(res.data);
|
||||
} catch (error) {
|
||||
console.error("获取命名空间信息失败:", error);
|
||||
return formatError(
|
||||
error.response?.data?.message || "获取命名空间信息失败",
|
||||
"NAMESPACE_ERROR"
|
||||
@@ -55,9 +44,8 @@ export const kvServerProvider = {
|
||||
async updateNamespaceInfo(data) {
|
||||
try {
|
||||
const serverUrl = getSetting("server.domain");
|
||||
const machineId = getSetting("device.uuid");
|
||||
|
||||
const res = await axios.put(`${serverUrl}/${machineId}/_info`, data, {
|
||||
const res = await axios.put(`${serverUrl}/kv/_info`, data, {
|
||||
headers: getHeaders(),
|
||||
});
|
||||
|
||||
@@ -70,61 +58,11 @@ export const kvServerProvider = {
|
||||
}
|
||||
},
|
||||
|
||||
async updatePassword(newPassword, oldPassword, passwordHint = null) {
|
||||
try {
|
||||
const serverUrl = getSetting("server.domain");
|
||||
const machineId = getSetting("device.uuid");
|
||||
|
||||
const res = await axios.post(
|
||||
`${serverUrl}/${machineId}/_password`,
|
||||
{
|
||||
password: newPassword,
|
||||
oldPassword,
|
||||
passwordHint,
|
||||
},
|
||||
{
|
||||
headers: getHeaders(),
|
||||
}
|
||||
);
|
||||
|
||||
if (res.status === 200) {
|
||||
// 更新本地存储的密码
|
||||
setSetting("namespace.password", newPassword || "");
|
||||
}
|
||||
|
||||
return res;
|
||||
} catch (error) {
|
||||
return formatError(
|
||||
error.response?.data?.message || "更新密码失败",
|
||||
"PASSWORD_ERROR"
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
async deletePassword() {
|
||||
try {
|
||||
const serverUrl = getSetting("server.domain");
|
||||
const machineId = getSetting("device.uuid");
|
||||
|
||||
const res = await axios.delete(`${serverUrl}/${machineId}/_password`, {
|
||||
headers: getHeaders(),
|
||||
});
|
||||
setSetting("namespace.password", "");
|
||||
return res;
|
||||
} catch (error) {
|
||||
return formatError(
|
||||
error.response?.data?.message || "删除密码失败",
|
||||
"PASSWORD_ERROR"
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
async loadData(key) {
|
||||
try {
|
||||
const serverUrl = getSetting("server.domain");
|
||||
const machineId = getSetting("device.uuid");
|
||||
|
||||
const res = await axios.get(`${serverUrl}/${machineId}/${key}`, {
|
||||
const res = await axios.get(`${serverUrl}/kv/${key}`, {
|
||||
headers: getHeaders(),
|
||||
});
|
||||
|
||||
@@ -144,8 +82,7 @@ export const kvServerProvider = {
|
||||
async saveData(key, data) {
|
||||
try {
|
||||
const serverUrl = getSetting("server.domain");
|
||||
const machineId = getSetting("device.uuid");
|
||||
await axios.post(`${serverUrl}/${machineId}/${key}`, data, {
|
||||
await axios.post(`${serverUrl}/kv/${key}`, data, {
|
||||
headers: getHeaders(),
|
||||
});
|
||||
return formatResponse(true);
|
||||
@@ -166,7 +103,7 @@ export const kvServerProvider = {
|
||||
* @param {number} options.limit - 每页返回的记录数,默认为 100
|
||||
* @param {number} options.skip - 跳过的记录数,默认为 0
|
||||
* @returns {Promise<Object>} 包含键名列表和分页信息的响应对象
|
||||
*
|
||||
*
|
||||
* 返回值示例:
|
||||
* {
|
||||
* keys: ["key1", "key2", "key3"],
|
||||
@@ -182,8 +119,7 @@ export const kvServerProvider = {
|
||||
async loadKeys(options = {}) {
|
||||
try {
|
||||
const serverUrl = getSetting("server.domain");
|
||||
const machineId = getSetting("device.uuid");
|
||||
|
||||
|
||||
// 设置默认参数
|
||||
const {
|
||||
sortBy = "key",
|
||||
@@ -191,7 +127,7 @@ export const kvServerProvider = {
|
||||
limit = 100,
|
||||
skip = 0
|
||||
} = options;
|
||||
|
||||
|
||||
// 构建查询参数
|
||||
const params = new URLSearchParams({
|
||||
sortBy,
|
||||
@@ -199,11 +135,11 @@ export const kvServerProvider = {
|
||||
limit: limit.toString(),
|
||||
skip: skip.toString()
|
||||
});
|
||||
|
||||
const res = await axios.get(`${serverUrl}/${machineId}/_keys?${params}`, {
|
||||
|
||||
const res = await axios.get(`${serverUrl}/kv/_keys?${params}`, {
|
||||
headers: getHeaders(),
|
||||
});
|
||||
|
||||
|
||||
return formatResponse(res.data);
|
||||
} catch (error) {
|
||||
if (error.response?.status === 404) {
|
||||
@@ -222,4 +158,4 @@ export const kvServerProvider = {
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
+29
-25
@@ -1,4 +1,3 @@
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
// 请求通知权限
|
||||
async function requestNotificationPermission() {
|
||||
if (Notification && Notification.requestPermission) {
|
||||
@@ -66,17 +65,11 @@ if (typeof window !== "undefined") {
|
||||
// 存储所有设置的localStorage键名
|
||||
const SETTINGS_STORAGE_KEY = "Classworks_settings";
|
||||
|
||||
/**
|
||||
* 生成UUID v4
|
||||
* @returns {string} 生成的UUID字符串
|
||||
*/
|
||||
function generateUUID() {
|
||||
return uuidv4();
|
||||
}
|
||||
|
||||
// 新增: Classworks云端存储的默认设置
|
||||
const classworksCloudDefaults = {
|
||||
"server.domain": "https://kv.wuyuan.dev",
|
||||
//"server.domain": "http://localhost:3030",
|
||||
"server.siteKey": "",
|
||||
};
|
||||
|
||||
@@ -88,26 +81,11 @@ const settingsDefinitions = {
|
||||
// 设备标识
|
||||
"device.uuid": {
|
||||
type: "string",
|
||||
default: generateUUID(),
|
||||
default: '00000000-0000-4000-8000-000000000000',
|
||||
description: "设备唯一标识符",
|
||||
icon: "mdi-identifier",
|
||||
},
|
||||
|
||||
// 命名空间设置
|
||||
"namespace.password": {
|
||||
type: "string",
|
||||
default: "",
|
||||
description: "命名空间访问密码",
|
||||
icon: "mdi-key",
|
||||
},
|
||||
"namespace.accessType": {
|
||||
type: "string",
|
||||
default: "readwrite",
|
||||
description: "访问权限类型",
|
||||
icon: "mdi-shield-lock",
|
||||
validate: (value) => ["readonly", "readwrite"].includes(value),
|
||||
},
|
||||
|
||||
// 存储设置
|
||||
"storage.persistOnLoad": {
|
||||
type: "boolean",
|
||||
@@ -213,9 +191,35 @@ const settingsDefinitions = {
|
||||
icon: "mdi-key-chain",
|
||||
// 用于后端验证请求的令牌,将作为请求头 x-site-key 发送
|
||||
},
|
||||
"server.kvToken": {
|
||||
type: "string",
|
||||
default: "",
|
||||
description: "KV授权令牌",
|
||||
icon: "mdi-shield-key",
|
||||
// 用于KV服务器认证的令牌,将作为请求头 x-app-token 发送
|
||||
},
|
||||
"server.authDomain": {
|
||||
type: "string",
|
||||
default: "https://kv.houlang.cloud",
|
||||
description: "授权服务器域名",
|
||||
icon: "mdi-shield-account",
|
||||
validate: (value) => {
|
||||
// 如果值为空,直接通过
|
||||
if (!value) return true;
|
||||
// 验证URL格式
|
||||
try {
|
||||
new URL(value);
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error("授权域名格式无效:", e);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
// 用于CSKV授权跳转的服务器域名
|
||||
},
|
||||
"server.provider": {
|
||||
type: "string",
|
||||
default: "kv-local",
|
||||
default: "classworkscloud",
|
||||
validate: (value) =>
|
||||
["kv-local", "kv-server", "classworkscloud"].includes(value),
|
||||
description: "数据提供者",
|
||||
|
||||
Reference in New Issue
Block a user