个人中心全部,模糊乱序搜索,类型筛选
Change-Id: Id635654fccccaea80bfbf4d1480abd55f7d12046
diff --git a/src/api/auth.js b/src/api/auth.js
index 4b569ef..c094a44 100644
--- a/src/api/auth.js
+++ b/src/api/auth.js
@@ -32,21 +32,25 @@
});
};
-
-export const getUserInfo = (token) => {
- return api.get('/user/info', { params: { token } });
+export const getUserInfo = async () => {
+ try {
+ const response = await api.get('/user/userInfo');
+ if (response.data.code === 200) {
+ return response.data.data;
+ }
+ throw new Error(response.data.message || '获取用户信息失败');
+ } catch (error) {
+ console.error('获取用户信息失败:', error);
+ throw error;
+ }
};
-// // 修改你的 API 请求
-// export const getUserInfo = () => {
-// const token = localStorage.getItem('token');
-// if (!token) {
-// throw new Error("Token 不存在");
-// }
-
-// return api.get('/user/info', {
-// headers: {
-// 'Authorization': `Bearer ${token}` // 必须带 Bearer 前缀
-// }
-// });
-// };
+export const isAdmin = async () => {
+ try {
+ const userInfo = await getUserInfo();
+ return userInfo.authority === 'ADMIN';
+ } catch (error) {
+ console.error('检查管理员权限失败:', error);
+ return false;
+ }
+};
diff --git a/src/api/auth.test.js b/src/api/auth.test.js
index c9ace4d..9de5691 100644
--- a/src/api/auth.test.js
+++ b/src/api/auth.test.js
@@ -1,11 +1,10 @@
import MockAdapter from 'axios-mock-adapter';
-import { api, login, register, getUserInfo } from './auth';
+import { api, login, register, getUserInfo, isAdmin } from './auth';
describe('auth API', () => {
let mockAxios;
beforeEach(() => {
- // 确保使用我们导出的 api 实例
mockAxios = new MockAdapter(api);
localStorage.clear();
});
@@ -16,28 +15,30 @@
describe('login', () => {
it('should send login request with username and password', async () => {
- const mockResponse = {
- code: 200,
- data: {
- token: 'mock-token',
- // 确保响应结构与实际API一致
- userInfo: { username: 'testuser' }
- },
- message: '登录成功'
- };
-
- mockAxios.onPost('/user/login').reply(200, mockResponse);
+ const mockResponse = {
+ code: 200,
+ data: {
+ token: 'mock-token',
+ userInfo: { username: 'testuser' }
+ },
+ message: '登录成功'
+ };
+
+ mockAxios.onPost('/user/login', undefined, {
+ params: { username: 'testuser', password: 'testpass' }
+ }).reply(200, mockResponse);
- const response = await login('testuser', 'testpass');
-
- expect(response.data).toEqual(mockResponse);
- // 检查token是否存入localStorage
- expect(localStorage.getItem('token')).toBe('mock-token');
- });
-
+ const response = await login('testuser', 'testpass');
+
+ expect(response.data).toEqual(mockResponse);
+ expect(localStorage.getItem('token')).toBe('mock-token');
+ });
it('should handle login failure', async () => {
- mockAxios.onPost('/user/login').reply(401);
+ mockAxios.onPost('/user/login').reply(401, {
+ code: 401,
+ message: '登录失败'
+ });
await expect(login('wronguser', 'wrongpass')).rejects.toThrow();
});
@@ -50,7 +51,9 @@
message: '注册成功'
};
- mockAxios.onPost('/user/regist').reply(200, mockResponse);
+ mockAxios.onPost('/user/regist', undefined, {
+ params: { username: 'newuser', password: 'newpass', code: 'invite123' }
+ }).reply(200, mockResponse);
const response = await register('newuser', 'newpass', 'invite123');
@@ -58,30 +61,66 @@
});
it('should handle registration failure', async () => {
- mockAxios.onPost('/user/regist').reply(400);
+ mockAxios.onPost('/user/regist').reply(400, {
+ code: 400,
+ message: '注册失败'
+ });
await expect(register('newuser', 'newpass', 'wrongcode')).rejects.toThrow();
});
});
describe('getUserInfo', () => {
- it('should send request with token to get user info', async () => {
+ it('should send request to get user info', async () => {
const mockResponse = {
code: 200,
- data: { username: 'testuser', role: 'user' }
+ data: { username: 'testuser', authority: 'USER' }
};
- mockAxios.onGet('/user/info').reply(200, mockResponse);
-
- const response = await getUserInfo('test-token');
+ mockAxios.onGet('/user/userInfo').reply(200, mockResponse);
+
+ const response = await getUserInfo();
- expect(response.data).toEqual(mockResponse);
+ expect(response).toEqual(mockResponse.data);
+ });
+
+ it('should handle unauthorized request', async () => {
+ mockAxios.onGet('/user/userInfo').reply(401);
+
+ await expect(getUserInfo()).rejects.toThrow('Request failed with status code 401');
+ });
+ });
+
+ describe('isAdmin', () => {
+ it('should return true when user is admin', async () => {
+ const mockResponse = {
+ code: 200,
+ data: { username: 'admin', authority: 'ADMIN' }
+ };
+
+ mockAxios.onGet('/user/userInfo').reply(200, mockResponse);
+
+ const result = await isAdmin();
+ expect(result).toBe(true);
});
- it('should handle unauthorized request', async () => {
- mockAxios.onGet('/user/info').reply(401);
+ it('should return false when user is not admin', async () => {
+ const mockResponse = {
+ code: 200,
+ data: { username: 'user', authority: 'USER' }
+ };
- await expect(getUserInfo('invalid-token')).rejects.toThrow();
+ mockAxios.onGet('/user/userInfo').reply(200, mockResponse);
+
+ const result = await isAdmin();
+ expect(result).toBe(false);
+ });
+
+ it('should return false when request fails', async () => {
+ mockAxios.onGet('/user/userInfo').reply(401);
+
+ const result = await isAdmin();
+ expect(result).toBe(false);
});
});
diff --git a/src/api/helpPost.js b/src/api/helpPost.js
index 4813aa3..92d6402 100644
--- a/src/api/helpPost.js
+++ b/src/api/helpPost.js
@@ -50,4 +50,11 @@
return api.delete(`/help/posts/${postId}`, {
params: { authorId }
});
+};
+
+
+export const searchPosts = (keyword, page = 1, size = 5) => {
+ return api.get('/help/posts/search', {
+ params: { keyword, page, size }
+ });
};
\ No newline at end of file
diff --git a/src/api/personal.js b/src/api/personal.js
new file mode 100644
index 0000000..949afb4
--- /dev/null
+++ b/src/api/personal.js
@@ -0,0 +1,181 @@
+// src/api/personal.js
+import { api } from './auth';
+
+/**
+ * 获取用户信息
+ * @returns {Promise<Object>} 用户信息对象
+ */
+export const getUserInfo = async () => {
+ try {
+ const response = await api.get('/user/userInfo');
+ if (response.data.code === 200) {
+ const userData = response.data.data;
+ return {
+ username: userData.username,
+ level: userData.level,
+ registTime: formatDate(userData.registTime),
+ magicPoints: userData.magicPoints,
+ upload: userData.upload,
+ download: userData.download,
+ shareRate: userData.shareRate.toFixed(2)
+ };
+ }
+ throw new Error(response.data.message || '获取用户信息失败');
+ } catch (error) {
+ console.error('获取用户信息失败:', error);
+ throw error;
+ }
+};
+
+export const formatFileSize = (bytes) => {
+ if (bytes < 1024) {
+ return bytes + ' B';
+ }
+ const kb = bytes / 1024;
+ if (kb < 1024) {
+ return kb.toFixed(2) + ' KB';
+ }
+ const mb = kb / 1024;
+ if (mb < 1024) {
+ return mb.toFixed(2) + ' MB';
+ }
+ const gb = mb / 1024;
+ return gb.toFixed(2) + ' GB';
+ };
+
+
+ export const getDownloadQuota = async () => {
+ try {
+ const response = await api.get('/user/allowDownload');
+ if (response.data.code === 200) {
+ const data = response.data.data;
+ return {
+ total: data.total, // 已经是字节
+ used: data.used,
+ remaining: data.remaining
+ };
+ }
+ throw new Error(response.data.message || '获取下载额度失败');
+ } catch (error) {
+ console.error('获取下载额度失败:', error);
+ throw error;
+ }
+ };
+
+// 修正后的时间格式化(正确处理时区)
+const formatDate = (dateString) => {
+ const date = new Date(dateString);
+ const year = date.getFullYear();
+ const month = String(date.getMonth() + 1).padStart(2, '0');
+ const day = String(date.getDate()).padStart(2, '0');
+ return `${year}-${month}-${day}`;
+ };
+
+
+ export const getDownloadProgress = async () => {
+ try {
+ const response = await api.get('/torrent/getProgress');
+ if (response.data.code === 200) {
+ return response.data.data.progresses;
+ }
+ throw new Error(response.data.message || '获取下载进度失败');
+ } catch (error) {
+ console.error('获取下载进度失败:', error);
+ throw error;
+ }
+ };
+
+ export const getUserTorrents = async (page = 1, size = 5) => {
+ try {
+ const response = await api.get('/torrent/get/torrentMyself', {
+ params: { page, size }
+ });
+ if (response.data.code === 200) {
+ const records = response.data.data.records.map(item => ({
+ ...item.torrent,
+ downloadCount: item.downloadCount,
+ formattedSize: item.formattedSize
+ }));
+ return {
+ records: records,
+ total: response.data.data.total
+ };
+ }
+ throw new Error(response.data.message || '获取上传记录失败');
+ } catch (error) {
+ console.error('获取上传记录失败:', error);
+ throw error;
+ }
+ };
+
+
+ export const deleteTorrent = async (id) => {
+ try {
+ const response = await api.delete(`/torrent/deleteTorrent/${id}`);
+ if (response.data.code === 200) {
+ return response.data;
+ }
+ throw new Error(response.data.message || '删除种子失败');
+ } catch (error) {
+ console.error('删除种子失败:', error);
+ throw error;
+ }
+ };
+
+
+ export const generateInviteCode = async () => {
+ try {
+ const response = await api.post('/invitecode/generate');
+ if (response.data.code === 200) {
+ return response.data.data.inviteCode;
+ }
+ throw new Error(response.data.message || '生成邀请码失败');
+ } catch (error) {
+ console.error('生成邀请码失败:', error);
+ throw error;
+ }
+ };
+
+ export const getUserInviteCodes = async () => {
+ try {
+ const response = await api.get('/invitecode/userInviteCode');
+ if (response.data.code === 200) {
+ return response.data.data.inviteCode;
+ }
+ throw new Error(response.data.message || '获取邀请码列表失败');
+ } catch (error) {
+ console.error('获取邀请码列表失败:', error);
+ throw error;
+ }
+ };
+
+ export const exchangeUpload = async (magicPoints) => {
+ try {
+ const response = await api.post('/user/exchangeUpload', {
+ magicPoint: magicPoints
+ });
+ if (response.data.code === 200) {
+ return response.data;
+ }
+ throw new Error(response.data.message || '兑换上传量失败');
+ } catch (error) {
+ console.error('兑换上传量失败:', error);
+ throw error;
+ }
+ };
+
+ export const updatePassword = async (oldPassword, newPassword) => {
+ try {
+ const response = await api.put('/user/password', {
+ oldPassword,
+ newPassword
+ });
+ if (response.data.code === 200) {
+ return response.data;
+ }
+ throw new Error(response.data.message || '修改密码失败');
+ } catch (error) {
+ console.error('修改密码失败:', error);
+ throw error;
+ }
+ };
diff --git a/src/api/torrent.js b/src/api/torrent.js
index 6c56fce..8a00e54 100644
--- a/src/api/torrent.js
+++ b/src/api/torrent.js
@@ -36,7 +36,7 @@
data: {
...response.data,
data: {
- torrent: response.data.data.post || response.data.data.torrent,
+ torrent: response.data.data.torrent, // 直接使用后端返回的格式化数据
comments: response.data.data.comments || []
}
}
@@ -52,4 +52,10 @@
export const addTorrentComment = (torrentId, commentData) => {
return api.post(`/torrent/${torrentId}/comments`, commentData);
+};
+
+export const searchTorrents = (keyword, page = 1, size = 5) => {
+ return api.get('/torrent/search', {
+ params: { keyword, page, size }
+ });
};
\ No newline at end of file
diff --git a/src/api/torrent.test.js b/src/api/torrent.test.js
index ca755c3..6515bdc 100644
--- a/src/api/torrent.test.js
+++ b/src/api/torrent.test.js
@@ -1,41 +1,134 @@
import MockAdapter from 'axios-mock-adapter';
-import { api } from './auth'; // Import api from auth
-import { createTorrent, getTorrents, getTorrentDetail, likeTorrent, addTorrentComment } from './torrent';
+import { api } from './auth';
+import {
+ createTorrent,
+ getTorrents,
+ getTorrentDetail,
+ likeTorrent,
+ addTorrentComment,
+ searchTorrents
+} from './torrent';
describe('种子资源API', () => {
let mockAxios;
beforeEach(() => {
mockAxios = new MockAdapter(api);
+ localStorage.setItem('token', 'test-token');
});
afterEach(() => {
mockAxios.restore();
+ localStorage.clear();
});
- // Test for getting torrent detail
+ describe('createTorrent - 创建种子', () => {
+ it('应该正确发送包含文件和数据的表单请求', async () => {
+ const mockFile = new File(['test'], 'test.torrent');
+ const torrentData = { name: '测试种子', description: '测试描述' };
+ const mockResponse = { code: 200, message: '创建成功' };
+
+ mockAxios.onPost('/torrent').reply((config) => {
+ expect(config.headers['Content-Type']).toBe('multipart/form-data');
+ expect(config.headers['Authorization']).toBe('Bearer test-token'); // 修改为包含Bearer
+ return [200, mockResponse];
+ });
+
+ const response = await createTorrent(torrentData, mockFile);
+ expect(response.data).toEqual(mockResponse);
+ });
+ });
+
+ describe('getTorrents - 获取种子列表', () => {
+ it('应该发送带分页参数的请求', async () => {
+ const mockResponse = {
+ code: 200,
+ data: {
+ list: [{ id: 1, name: '种子1' }, { id: 2, name: '种子2' }],
+ total: 2
+ }
+ };
+
+ mockAxios.onGet('/torrent', { params: { page: 2, size: 10 } })
+ .reply(200, mockResponse);
+
+ const response = await getTorrents(2, 10);
+ expect(response.data).toEqual(mockResponse);
+ });
+ });
+
describe('getTorrentDetail - 获取种子详情', () => {
it('应该规范化返回的数据结构', async () => {
- const mockData = {
+ const mockResponse = {
+ code: 200,
data: {
- post: { id: '123', name: '测试种子' },
+ torrent: { id: '123', name: '测试种子' },
comments: [{ id: '1', content: '评论1' }]
}
};
- mockAxios.onGet('/torrent/123').reply(200, mockData);
+
+ mockAxios.onGet('/torrent/123').reply(200, mockResponse);
const response = await getTorrentDetail('123');
- expect(response.data.data.torrent.name).toBe('测试种子'); // Corrected key to `post.name`
+ expect(response.data.data.torrent.name).toBe('测试种子');
expect(response.data.data.comments).toHaveLength(1);
});
+
+ it('应该处理没有评论的情况', async () => {
+ const mockResponse = {
+ code: 200,
+ data: {
+ torrent: { id: '123', name: '测试种子' },
+ comments: null
+ }
+ };
+
+ mockAxios.onGet('/torrent/123').reply(200, mockResponse);
+
+ const response = await getTorrentDetail('123');
+ expect(response.data.data.comments).toEqual([]);
+ });
});
- // Test for liking a torrent
describe('likeTorrent - 点赞种子', () => {
- it('应该成功发送点赞请求', async () => {
- mockAxios.onPost('/torrent/t123/like').reply(200, { code: 200 });
- const response = await likeTorrent('t123');
- expect(response.status).toBe(200);
+ it('应该发送点赞请求', async () => {
+ const mockResponse = { code: 200, message: '点赞成功' };
+ mockAxios.onPost('/torrent/123/like').reply(200, mockResponse);
+
+ const response = await likeTorrent('123');
+ expect(response.data).toEqual(mockResponse);
});
});
-});
+
+ describe('addTorrentComment - 添加种子评论', () => {
+ it('应该发送评论数据', async () => {
+ const commentData = { content: '测试评论' };
+ const mockResponse = { code: 200, message: '评论成功' };
+
+ mockAxios.onPost('/torrent/123/comments', commentData)
+ .reply(200, mockResponse);
+
+ const response = await addTorrentComment('123', commentData);
+ expect(response.data).toEqual(mockResponse);
+ });
+ });
+
+ describe('searchTorrents - 搜索种子', () => {
+ it('应该发送带搜索关键词和分页的请求', async () => {
+ const mockResponse = {
+ code: 200,
+ data: {
+ list: [{ id: 1, name: '匹配的种子' }],
+ total: 1
+ }
+ };
+
+ mockAxios.onGet('/torrent/search', {
+ params: { keyword: '测试', page: 1, size: 5 }
+ }).reply(200, mockResponse);
+
+ const response = await searchTorrents('测试');
+ expect(response.data).toEqual(mockResponse);
+ });
+ });
+});
\ No newline at end of file