@kne/fastify-account 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,18 +1,43 @@
1
1
 
2
- # fastify-user
2
+ # fastify-account
3
3
 
4
4
 
5
5
  ### 描述
6
6
 
7
- 用于用户注册登录认证
7
+ 用于用户注册登录认证.
8
8
 
9
9
 
10
10
  ### 安装
11
11
 
12
12
  ```shell
13
- npm i --save @kne/fastify-user
13
+ npm i --save @kne/fastify-account
14
14
  ```
15
15
 
16
+
17
+ ### 概述
18
+
19
+ #### 功能模块
20
+ - **账号管理**:提供用户注册、登录、密码修改、忘记密码等功能。
21
+ - **用户信息管理**:支持用户信息的获取和更新。
22
+ - **验证码服务**:支持邮箱和短信验证码的发送与验证。
23
+
24
+ #### 技术栈
25
+ - **后端框架**:Fastify
26
+ - **数据库**:Sequelize(支持多种数据库)
27
+ - **认证**:JWT(JSON Web Token)
28
+ - **密码加密**:bcryptjs
29
+ - **工具库**:Lodash、Day.js
30
+
31
+ #### 核心模块
32
+ - **models**:定义数据模型(用户、账号、验证码等)。
33
+ - **services**:业务逻辑层,处理核心功能。
34
+ - **controllers**:API接口层,定义路由和请求处理。
35
+
36
+ #### 项目特点
37
+ - 模块化设计,易于扩展和维护。
38
+ - 支持多租户功能。
39
+ - 提供详细的错误处理和日志记录。
40
+
16
41
  ### 示例
17
42
 
18
43
  #### 示例代码
@@ -21,7 +46,24 @@ npm i --save @kne/fastify-user
21
46
 
22
47
  ### API
23
48
 
24
- | 属性名 | 说明 | 类型 | 默认值 |
25
- |-----|----|----|-----|
26
- | | | | |
49
+ #### 账号管理
50
+
51
+ | 路径 | 方法 | 描述 | 参数 |
52
+ |------|------|------|------|
53
+ | `/api/account/v1.0.0/account/sendEmailCode` | POST | 发送登录邮箱验证码 | `email` (string), `type` (number), `options` (object) |
54
+ | `/api/account/v1.0.0/account/sendSMSCode` | POST | 发送登录短信验证码 | `phone` (string), `type` (number), `options` (object) |
55
+ | `/api/account/v1.0.0/account/validateCode` | POST | 验证码验证 | `name` (string), `type` (number), `code` (string) |
56
+ | `/api/account/v1.0.0/account/accountIsExists` | POST | 账号是否已存在 | `phone` (string) 或 `email` (string) |
57
+ | `/api/account/v1.0.0/account/register` | POST | 注册账号 | `phone` (string) 或 `email` (string), `password` (string), `code` (string), 其他可选字段 |
58
+ | `/api/account/v1.0.0/account/login` | POST | 登录 | `type` (string), `email` (string) 或 `phone` (string), `password` (string) |
59
+ | `/api/account/v1.0.0/account/modifyPassword` | POST | 修改密码 | `email` (string) 或 `phone` (string), `newPwd` (string), `oldPwd` (string) |
60
+ | `/api/account/v1.0.0/account/resetPassword` | POST | 重置密码 | `newPwd` (string), `token` (string) |
61
+ | `/api/account/v1.0.0/account/forgetPwd` | POST | 忘记密码 | `email` (string) 或 `phone` (string) |
62
+ | `/api/account/v1.0.0/account/parseResetToken` | POST | 通过token获取name | `token` (string) |
63
+
64
+ #### 用户信息管理
27
65
 
66
+ | 路径 | 方法 | 描述 | 参数 |
67
+ |------|------|------|------|
68
+ | `/api/account/v1.0.0/user/getUserInfo` | GET | 获取用户信息 | 无 |
69
+ | `/api/account/v1.0.0/user/saveUserInfo` | POST | 更新用户信息 | `avatar` (string), `nickname` (string), `email` (string), `phone` (string), `gender` (string), `birthday` (string), `description` (string) |
@@ -2,58 +2,34 @@ const user = ({ DataTypes, definePrimaryType }) => {
2
2
  return {
3
3
  model: {
4
4
  nickname: {
5
- type: DataTypes.STRING,
6
- comment: '用户昵称'
7
- },
8
- email: {
9
- type: DataTypes.STRING,
10
- comment: '用户邮箱'
11
- },
12
- phone: {
13
- type: DataTypes.STRING,
14
- comment: '用户手机号'
15
- },
16
- userAccountId: definePrimaryType('userAccountId', {
17
- allowNull: false,
18
- comment: '当前账号id'
19
- }),
20
- status: {
21
- type: DataTypes.INTEGER,
22
- defaultValue: 0,
23
- comment: '0:正常,10:初始化未激活,需要用户设置密码后使用,11:已禁用,12:已关闭'
24
- },
25
- avatar: {
26
- type: DataTypes.STRING,
27
- comment: '头像fileId'
28
- },
29
- gender: {
30
- type: DataTypes.STRING,
31
- comment: 'F:女,M:男'
32
- },
33
- birthday: {
34
- type: DataTypes.DATE,
35
- comment: '出生日期'
36
- },
37
- description: {
38
- type: DataTypes.TEXT,
39
- comment: '个人描述'
40
- },
41
- isSuperAdmin: {
42
- type: DataTypes.BOOLEAN,
43
- comment: '是否是平台超级管理员'
44
- }
45
- },
46
- options: {
47
- indexes: [
48
- {
49
- unique: true,
50
- fields: ['email', 'deleted_at']
51
- },
52
- {
53
- unique: true,
54
- fields: ['phone', 'deleted_at']
5
+ type: DataTypes.STRING, comment: '用户昵称'
6
+ }, email: {
7
+ type: DataTypes.STRING, comment: '用户邮箱', set(value) {
8
+ this.setDataValue('email', value ? value.toLowerCase() : value);
55
9
  }
56
- ]
10
+ }, phone: {
11
+ type: DataTypes.STRING, comment: '用户手机号'
12
+ }, userAccountId: definePrimaryType('userAccountId', {
13
+ allowNull: false, comment: '当前账号id'
14
+ }), status: {
15
+ type: DataTypes.INTEGER, defaultValue: 0, comment: '0:正常,10:初始化未激活,需要用户设置密码后使用,11:已禁用,12:已关闭'
16
+ }, avatar: {
17
+ type: DataTypes.STRING, comment: '头像fileId'
18
+ }, gender: {
19
+ type: DataTypes.STRING, comment: 'F:女,M:男'
20
+ }, birthday: {
21
+ type: DataTypes.DATE, comment: '出生日期'
22
+ }, description: {
23
+ type: DataTypes.TEXT, comment: '个人描述'
24
+ }, isSuperAdmin: {
25
+ type: DataTypes.BOOLEAN, comment: '是否是平台超级管理员'
26
+ }
27
+ }, options: {
28
+ indexes: [{
29
+ unique: true, fields: ['email', 'deleted_at']
30
+ }, {
31
+ unique: true, fields: ['phone', 'deleted_at']
32
+ }]
57
33
  }
58
34
  };
59
35
  };
@@ -122,7 +122,7 @@ const accountService = fp(async (fastify, options) => {
122
122
  };
123
123
  (() => {
124
124
  if (type === 'email') {
125
- query.email = email;
125
+ query.email = email.toLowerCase();
126
126
  return;
127
127
  }
128
128
  if (type === 'phone') {
@@ -36,19 +36,17 @@ const userService = fp(async (fastify, options) => {
36
36
  const accountIsExists = async ({ email, phone }, currentUser) => {
37
37
  const query = [];
38
38
  if (email && email !== get(currentUser, 'email')) {
39
- query.push({ email });
39
+ query.push({ email: email.toLowerCase() });
40
40
  }
41
41
  if (phone && phone !== get(currentUser, 'phone')) {
42
42
  query.push({ phone });
43
43
  }
44
44
 
45
- return (
46
- (await models.user.count({
47
- where: {
48
- [Op.or]: query
49
- }
50
- })) > 0
51
- );
45
+ return ((await models.user.count({
46
+ where: {
47
+ [Op.or]: query
48
+ }
49
+ })) > 0);
52
50
  };
53
51
 
54
52
  const addUser = async ({ avatar, nickname, gender, birthday, description, phone, email, password, status }) => {
@@ -60,15 +58,7 @@ const userService = fp(async (fastify, options) => {
60
58
  }
61
59
  const account = await models.userAccount.create(await services.account.passwordEncryption(password));
62
60
  const user = await models.user.create({
63
- avatar,
64
- nickname,
65
- gender,
66
- birthday,
67
- description,
68
- phone,
69
- email,
70
- status,
71
- userAccountId: account.id
61
+ avatar, nickname, gender, birthday, description, phone, email, status, userAccountId: account.id
72
62
  });
73
63
  await account.update({ belongToUserId: user.id });
74
64
 
@@ -78,28 +68,43 @@ const userService = fp(async (fastify, options) => {
78
68
  const getUserList = async ({ filter, perPage, currentPage }) => {
79
69
  const queryFilter = {};
80
70
 
81
- ['nickname'].forEach(key => {
71
+ ['nickname', 'phone', 'email'].forEach(key => {
82
72
  if (filter && filter[key]) {
83
73
  queryFilter[key] = {
84
74
  [Op.like]: `%${filter[key]}%`
85
75
  };
86
76
  }
87
77
  });
78
+ ['status'].forEach(key => {
79
+ if (filter && filter[key]) {
80
+ queryFilter[key] = filter[key];
81
+ }
82
+ });
83
+ if (filter?.isSuperAdmin !== undefined) {
84
+ if (filter.isSuperAdmin === 'true') {
85
+ queryFilter.isSuperAdmin = true;
86
+ } else {
87
+ queryFilter.isSuperAdmin = {
88
+ [Op.or]: [false, null]
89
+ };
90
+ }
91
+ }
92
+
88
93
  const { count, rows } = await models.user.findAndCountAll({
89
94
  where: queryFilter,
90
95
  offset: perPage * (currentPage - 1),
91
- limit: perPage
96
+ limit: perPage,
97
+ order: [['createdAt', 'DESC']]
92
98
  });
93
99
  return {
94
100
  pageData: rows.map(item => {
95
101
  return Object.assign({}, item.get({ pain: true }));
96
- }),
97
- totalCount: count
102
+ }), totalCount: count
98
103
  };
99
104
  };
100
105
 
101
106
  const saveUser = async ({ id, ...otherInfo }) => {
102
- const user = await getUserInstance({id});
107
+ const user = await getUserInstance({ id });
103
108
 
104
109
  if ((await accountIsExists({ phone: otherInfo.phone, email: otherInfo.email }, user)) > 0) {
105
110
  throw new Error('手机号或者邮箱都不能重复');
@@ -127,14 +132,7 @@ const userService = fp(async (fastify, options) => {
127
132
  };
128
133
 
129
134
  services.user = {
130
- getUserInstance,
131
- getUser,
132
- addUser,
133
- saveUser,
134
- accountIsExists,
135
- getUserList,
136
- setSuperAdmin,
137
- setUserStatus
135
+ getUserInstance, getUser, addUser, saveUser, accountIsExists, getUserList, setSuperAdmin, setUserStatus
138
136
  };
139
137
  });
140
138
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kne/fastify-account",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "用于用户注册登录认证.",
5
5
  "main": "index.js",
6
6
  "scripts": {