个人中心全部,模糊乱序搜索,类型筛选

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