🔱: [server] sync upgrade with 21 commits [trident-sync]

Update README.md
This commit is contained in:
xiaojunnuo
2023-01-29 15:26:58 +08:00
parent 62e3945d30
commit fbde7cbd93
59 changed files with 2126 additions and 2 deletions
@@ -0,0 +1,63 @@
import {
ALL,
Body,
Controller,
Inject,
Post,
Provide,
Query,
} from '@midwayjs/decorator';
import { CrudController } from '../../../basic/crud-controller';
import { PermissionService } from '../service/permission-service';
/**
* 权限资源
*/
@Provide()
@Controller('/api/sys/authority/permission')
export class PermissionController extends CrudController<PermissionService> {
@Inject()
service: PermissionService;
getService() {
return this.service;
}
@Post('/page')
async page(
@Body(ALL)
body
) {
return await super.page(body);
}
@Post('/add')
async add(
@Body(ALL)
bean
) {
return await super.add(bean);
}
@Post('/update')
async update(
@Body(ALL)
bean
) {
return await super.update(bean);
}
@Post('/delete')
async delete(
@Query('id')
id
) {
return await super.delete(id);
}
@Post('/tree')
async tree() {
const tree = await this.service.tree({});
return this.ok(tree);
}
}
@@ -0,0 +1,96 @@
import {
ALL,
Body,
Controller,
Inject,
Post,
Provide,
Query,
} from '@midwayjs/decorator';
import { CrudController } from '../../../basic/crud-controller';
import { RoleService } from '../service/role-service';
/**
* 系统用户
*/
@Provide()
@Controller('/api/sys/authority/role')
export class RoleController extends CrudController<RoleService> {
@Inject()
service: RoleService;
getService() {
return this.service;
}
@Post('/page')
async page(
@Body(ALL)
body
) {
return await super.page(body);
}
@Post('/list')
async list() {
const ret = await this.service.find({});
return this.ok(ret);
}
@Post('/add')
async add(
@Body(ALL)
bean
) {
return await super.add(bean);
}
@Post('/update')
async update(
@Body(ALL)
bean
) {
return await super.update(bean);
}
@Post('/delete')
async delete(
@Query('id')
id
) {
return await super.delete(id);
}
@Post('/getPermissionTree')
async getPermissionTree(
@Query('id')
id
) {
const ret = await this.service.getPermissionTreeByRoleId(id);
return this.ok(ret);
}
@Post('/getPermissionIds')
async getPermissionIds(
@Query('id')
id
) {
const ret = await this.service.getPermissionIdsByRoleId(id);
return this.ok(ret);
}
/**
* 给角色授予权限
* @param id
*/
@Post('/authz')
async authz(
@Body('roleId')
roleId,
@Body('permissionIds')
permissionIds
) {
await this.service.authz(roleId, permissionIds);
return this.ok(null);
}
}
@@ -0,0 +1,119 @@
import {
Provide,
Controller,
Post,
Inject,
Body,
Query,
ALL,
} from '@midwayjs/decorator';
import { UserService } from '../service/user-service';
import { CrudController } from '../../../basic/crud-controller';
import { RoleService } from '../service/role-service';
import { PermissionService } from '../service/permission-service';
/**
* 系统用户
*/
@Provide()
@Controller('/api/sys/authority/user')
export class UserController extends CrudController<UserService> {
@Inject()
service: UserService;
@Inject()
roleService: RoleService;
@Inject()
permissionService: PermissionService;
getService() {
return this.service;
}
@Post('/page')
async page(
@Body(ALL)
body
) {
const ret = await super.page(body);
const users = ret.data.records;
//获取roles
const userIds = users.map((item) => item.id);
const userRoles = await this.roleService.getByUserIds(userIds);
const userRolesMap = new Map();
for (const ur of userRoles) {
let roles = userRolesMap.get(ur.userId);
if (roles == null) {
roles = [];
userRolesMap.set(ur.userId, roles);
}
roles.push(ur.roleId);
}
for (const record of users) {
//withRoles
record.roles = userRolesMap.get(record.id);
//删除密码字段
delete record.password;
}
return ret;
}
@Post('/add')
async add(
@Body(ALL)
bean
) {
return await super.add(bean);
}
@Post('/update')
async update(
@Body(ALL)
bean
) {
return await super.update(bean);
}
@Post('/delete')
async delete(
@Query('id')
id
) {
return await super.delete(id);
}
/**
* 当前登录用户的个人信息
*/
@Post('/mine')
public async mine() {
const id = this.ctx.user.id;
const info = await this.service.info(id, ['password']);
return this.ok(info);
}
/**
* 当前登录用户的权限列表
*/
@Post('/permissions')
public async permissions() {
const id = this.ctx.user.id;
const permissions = await this.service.getUserPermissions(id);
return this.ok(permissions);
}
/**
* 当前登录用户的权限树形列表
*/
@Post('/permissionTree')
public async permissionTree() {
const id = this.ctx.user.id;
const permissions = await this.service.getUserPermissions(id);
const tree = this.permissionService.buildTree(permissions);
return this.ok(tree);
}
}
@@ -0,0 +1,40 @@
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
/**
* 权限
*/
@Entity('sys_permission')
export class PermissionEntity {
@PrimaryGeneratedColumn()
id: number;
@Column({ comment: '标题', length: 100 })
title: string;
/**
* 权限代码
* 示例:sys:user:read
*/
@Column({ comment: '权限代码', length: 100, nullable: true })
permission: string;
@Column({ name: 'parent_id', comment: '父节点ID', default: -1 })
parentId: number;
@Column({ comment: '排序号' })
sort: number;
@Column({
name: 'create_time',
comment: '创建时间',
default: () => 'CURRENT_TIMESTAMP',
})
createTime: Date;
@Column({
name: 'update_time',
comment: '修改时间',
default: () => 'CURRENT_TIMESTAMP',
})
updateTime: Date;
// @ManyToMany(type => RoleEntity, res => res.permissions)
// roles: RoleEntity[];
}
@@ -0,0 +1,12 @@
import { Entity, PrimaryColumn } from 'typeorm';
/**
* 角色权限多对多
*/
@Entity('sys_role_permission')
export class RolePermissionEntity {
@PrimaryColumn({ name: 'role_id' })
roleId: number;
@PrimaryColumn({ name: 'permission_id' })
permissionId: number;
}
@@ -0,0 +1,43 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
/**
* 角色
*/
@Entity('sys_role')
export class RoleEntity {
@PrimaryGeneratedColumn()
id: number;
@Index({ unique: true })
@Column({ comment: '角色名称', length: 100 })
name: string;
@Column({
name: 'create_time',
comment: '创建时间',
default: () => 'CURRENT_TIMESTAMP',
})
createTime: Date;
@Column({
name: 'update_time',
comment: '修改时间',
default: () => 'CURRENT_TIMESTAMP',
})
updateTime: Date;
// @ManyToMany(type => PermissionEntity, res => res.roles)
// @JoinTable({
// name: 'sys_role_resources',
// joinColumn: {
// name: 'roleId',
// referencedColumnName: 'id',
// },
// inverseJoinColumn: {
// name: 'resourceId',
// referencedColumnName: 'id',
// },
// })
// resources: PermissionEntity[];
// @ManyToMany(type => UserEntity, res => res.roles)
// users: UserEntity[];
}
@@ -0,0 +1,12 @@
import { Entity, PrimaryColumn } from 'typeorm';
/**
* 用户角色多对多
*/
@Entity('sys_user_role')
export class UserRoleEntity {
@PrimaryColumn({ name: 'role_id' })
roleId: number;
@PrimaryColumn({ name: 'user_id' })
userId: number;
}
@@ -0,0 +1,63 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
/**
* 系统用户
*/
@Entity('sys_user')
export class UserEntity {
@PrimaryGeneratedColumn()
id: number;
@Index({ unique: true })
@Column({ comment: '用户名', length: 100 })
username: string;
@Column({ comment: '密码', length: 100 })
password: string;
@Column({ name: 'nick_name', comment: '昵称', length: 100, nullable: true })
nickName: string;
@Column({ comment: '头像', length: 255, nullable: true })
avatar: string;
@Column({ name: 'phone_code', comment: '区号', length: 20, nullable: true })
phoneCode: string;
@Column({ comment: '手机', length: 20, nullable: true })
mobile: string;
@Column({ comment: '邮箱', length: 50, nullable: true })
email: string;
@Column({ comment: '备注', length: 100, nullable: true })
remark: string;
@Column({ comment: '状态 0:禁用 1:启用', default: 1, type: 'int' })
status: number;
@Column({
name: 'create_time',
comment: '创建时间',
default: () => 'CURRENT_TIMESTAMP',
})
createTime: Date;
@Column({
name: 'update_time',
comment: '修改时间',
default: () => 'CURRENT_TIMESTAMP',
})
updateTime: Date;
// @ManyToMany(type => RoleEntity, res => res.users)
// @JoinTable({
// name: 'sys_user_roles',
// joinColumn: {
// name: 'userId',
// referencedColumnName: 'id',
// },
// inverseJoinColumn: {
// name: 'roleId',
// referencedColumnName: 'id',
// },
// })
// roles: RoleEntity[];
}
@@ -0,0 +1,17 @@
import { EnumItem } from '../../../basic/enum-item';
import * as _ from 'lodash';
class ResourceTypes {
MENU = new EnumItem('menu', '菜单', 'blue');
BTN = new EnumItem('btn', '按钮', 'green');
ROUTE = new EnumItem('route', '路由', 'red');
names() {
const list = [];
_.forEach(this, (item, key) => {
list.push(item);
});
return list;
}
}
export const ResourceTypeEnum = new ResourceTypes();
@@ -0,0 +1,52 @@
import { Provide } from '@midwayjs/decorator';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { BaseService } from '../../../basic/base-service';
import { PermissionEntity } from '../entity/permission';
/**
* 权限资源
*/
@Provide()
export class PermissionService extends BaseService {
@InjectEntityModel(PermissionEntity)
repository: Repository<PermissionEntity>;
getRepository() {
return this.repository;
}
async tree(options: any = {}) {
if (options.order == null) {
options.order = {
sort: 'ASC',
};
}
const list = await this.find(options);
return this.buildTree(list);
}
buildTree(list: any) {
const idMap = {};
const root = [];
for (const item of list) {
idMap[item.id] = item;
if (item.parentId == null || item.parentId <= 0) {
root.push(item);
}
}
for (const item of list) {
if (item.parentId > 0) {
const parent = idMap[item.parentId];
if (parent) {
if (parent.children == null) {
parent.children = [];
}
parent.children.push(item);
}
}
}
return root;
}
}
@@ -0,0 +1,18 @@
import { Provide } from '@midwayjs/decorator';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { BaseService } from '../../../basic/base-service';
import { RolePermissionEntity } from '../entity/role-permission';
/**
* 角色->权限
*/
@Provide()
export class RolePermissionService extends BaseService {
@InjectEntityModel(RolePermissionEntity)
repository: Repository<RolePermissionEntity>;
getRepository() {
return this.repository;
}
}
@@ -0,0 +1,101 @@
import { Inject, Provide } from '@midwayjs/decorator';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { In, Repository } from 'typeorm';
import { BaseService } from '../../../basic/base-service';
import { RoleEntity } from '../entity/role';
import { UserRoleService } from './user-role-service';
import { RolePermissionEntity } from '../entity/role-permission';
import { PermissionService } from './permission-service';
import * as _ from 'lodash';
import { RolePermissionService } from './role-permission-service';
/**
* 角色
*/
@Provide()
export class RoleService extends BaseService {
@InjectEntityModel(RoleEntity)
repository: Repository<RoleEntity>;
@Inject()
userRoleService: UserRoleService;
@Inject()
permissionService: PermissionService;
@Inject()
rolePermissionService: RolePermissionService;
getRepository() {
return this.repository;
}
async getRoleIdsByUserId(id: any) {
const userRoles = await this.userRoleService.find({
where: { userId: id },
});
return userRoles.map(item => item.roleId);
}
async getByUserIds(ids: any) {
return await this.userRoleService.find({
where: {
userId: In(ids),
},
});
}
async getPermissionByRoleIds(roleIds: any) {
return await this.permissionService.repository
.createQueryBuilder('permission')
.innerJoinAndSelect(
RolePermissionEntity,
'rp',
'rp.permissionId = permission.id and rp.roleId in (:...roleIds)',
{ roleIds }
)
.getMany();
}
async addRoles(userId: number, roles) {
if (roles == null || roles.length === 0) {
return;
}
for (const roleId of roles) {
await this.userRoleService.add({
userId,
roleId,
});
}
}
async updateRoles(userId, roles) {
if (roles == null) {
return;
}
const oldRoleIds = await this.getRoleIdsByUserId(userId);
if (_.xor(roles, oldRoleIds).length === 0) {
//如果两个数组相等,则不修改
return;
}
//先删除所有
await this.userRoleService.delete({ userId });
//再添加
await this.addRoles(userId, roles);
}
async getPermissionTreeByRoleId(id: any) {
const list = await this.getPermissionByRoleIds([id]);
return this.permissionService.buildTree(list);
}
async getPermissionIdsByRoleId(id: any) {
const list = await this.getPermissionByRoleIds([id]);
return list.map(item => item.id);
}
async authz(roleId: any, permissionIds: any) {
await this.rolePermissionService.delete({ roleId });
for (const permissionId of permissionIds) {
await this.rolePermissionService.add({
roleId,
permissionId,
});
}
}
}
@@ -0,0 +1,18 @@
import { Provide } from '@midwayjs/decorator';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { BaseService } from '../../../basic/base-service';
import { UserRoleEntity } from '../entity/user-role';
/**
* 用户->角色
*/
@Provide()
export class UserRoleService extends BaseService {
@InjectEntityModel(UserRoleEntity)
repository: Repository<UserRoleEntity>;
getRepository() {
return this.repository;
}
}
@@ -0,0 +1,113 @@
import { Inject, Provide } from '@midwayjs/decorator';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { UserEntity } from '../entity/user';
import * as _ from 'lodash';
import * as md5 from 'md5';
import { CommonException } from '../../../basic/exception/common-exception';
import { BaseService } from '../../../basic/base-service';
import { logger } from '../../../utils/logger';
import { RoleService } from './role-service';
import { PermissionService } from './permission-service';
import { UserRoleService } from './user-role-service';
/**
* 系统用户
*/
@Provide()
export class UserService extends BaseService {
@InjectEntityModel(UserEntity)
repository: Repository<UserEntity>;
@Inject()
roleService: RoleService;
@Inject()
permissionService: PermissionService;
@Inject()
userRoleService: UserRoleService;
getRepository() {
return this.repository;
}
/**
* 获得个人信息
*/
async mine() {
const info = await this.repository.findOne({
where: {
id: this.ctx.user.id,
}
});
delete info.password;
return info;
}
/**
* 新增
* @param param
*/
async add(param) {
const exists = await this.repository.findOne({
where:{
username: param.username,
}
});
if (!_.isEmpty(exists)) {
throw new CommonException('用户名已经存在');
}
const password = param.password ?? '123456';
param.password = md5(password); // 默认密码 建议未改密码不能登陆
await super.add(param);
//添加角色
if (param.roles && param.roles.length > 0) {
await this.roleService.addRoles(param.id, param.roles);
}
return param.id;
}
/**
* 修改
* @param param 数据
*/
async update(param) {
if (param.id == null) {
throw new CommonException('id不能为空');
}
const userInfo = await this.repository.findOne({
where:{ id: param.id }
});
if (!userInfo) {
throw new CommonException('用户不存在');
}
delete param.username;
if (!_.isEmpty(param.password)) {
param.password = md5(param.password);
} else {
delete param.password;
}
await super.update(param);
await this.roleService.updateRoles(param.id, param.roles);
}
async findOne(param) {
return this.repository.findOne({
where:param
});
}
checkPassword(rawPassword: any, md5Password: any) {
logger.info('md5', md5('123456'));
return md5(rawPassword) === md5Password;
}
/**
* 获取用户的菜单资源列表
* @param id
*/
async getUserPermissions(id: any) {
const roleIds = await this.roleService.getRoleIdsByUserId(id);
return await this.roleService.getPermissionByRoleIds(roleIds);
}
}
@@ -0,0 +1,56 @@
import { Rule,RuleType } from '@midwayjs/validate';
import { ALL, Inject } from '@midwayjs/decorator';
import { Body } from '@midwayjs/decorator';
import { Controller, Post, Provide } from '@midwayjs/decorator';
import { BaseController } from '../../../basic/base-controller';
import { CodeService } from '../service/code-service';
export class SmsCodeReq {
@Rule(RuleType.number().required())
phoneCode: number;
@Rule(RuleType.string().required())
mobile: string;
@Rule(RuleType.string().required().max(10))
randomStr: string;
@Rule(RuleType.number().required().max(4))
imgCode: string;
}
// const enumsMap = {};
// glob('src/modules/**/enums/*.ts', {}, (err, matches) => {
// console.log('matched', matches);
// for (const filePath of matches) {
// const module = require('/' + filePath);
// console.log('modules', module);
// }
// });
/**
*/
@Provide()
@Controller('/api/basic')
export class BasicController extends BaseController {
@Inject()
codeService: CodeService;
@Post('/sendSmsCode')
public sendSmsCode(
@Body(ALL)
body: SmsCodeReq
) {
// 设置缓存内容
return this.ok(null);
}
@Post('/captcha')
public async getCaptcha(
@Body()
randomStr
) {
console.assert(randomStr < 10, 'randomStr 过长');
const captcha = await this.codeService.generateCaptcha(randomStr);
return this.ok(captcha.data);
}
}
@@ -0,0 +1,57 @@
import { Inject, Provide } from '@midwayjs/decorator';
import { CacheManager } from '@midwayjs/cache';
const svgCaptcha = require('svg-captcha');
// {data: '<svg.../svg>', text: 'abcd'}
/**
*/
@Provide()
export class CodeService {
@Inject()
cache: CacheManager; // 依赖注入CacheManager
/**
*/
async generateCaptcha(randomStr) {
console.assert(randomStr < 10, 'randomStr 过长');
const c = svgCaptcha.create();
//{data: '<svg.../svg>', text: 'abcd'}
const imgCode = c.text; // = RandomUtil.randomStr(4, true);
await this.cache.set('imgCode:' + randomStr, imgCode, {
ttl: 2 * 60 * 1000, //过期时间 2分钟
});
return c;
}
async getCaptchaText(randomStr) {
return await this.cache.get('imgCode:' + randomStr);
}
async removeCaptcha(randomStr) {
await this.cache.del('imgCode:' + randomStr);
}
async checkCaptcha(randomStr, userCaptcha) {
const code = await this.getCaptchaText(randomStr);
if (code == null) {
throw new Error('验证码已过期');
}
if (code !== userCaptcha) {
throw new Error('验证码不正确');
}
return true;
}
/**
*/
async sendSms(phoneCode, mobile, smsCode) {
console.assert(phoneCode != null && mobile != null, '手机号不能为空');
console.assert(smsCode != null, '验证码不能为空');
}
/**
* loginBySmsCode
*/
async loginBySmsCode(user, smsCode) {
console.assert(user.mobile != null, '手机号不能为空');
}
}
@@ -0,0 +1,31 @@
import {
Body,
Controller,
Inject,
Post,
Provide,
ALL,
} from '@midwayjs/decorator';
import { LoginService } from '../service/login-service';
import { BaseController } from '../../../basic/base-controller';
/**
*/
@Provide()
@Controller('/api/')
export class LoginController extends BaseController {
@Inject()
loginService: LoginService;
@Post('/login')
public async login(
@Body(ALL)
user
) {
const token = await this.loginService.login(user);
return this.ok(token);
}
@Post('/logout')
public logout() {}
}
@@ -0,0 +1,52 @@
import { Config, Inject, Provide } from '@midwayjs/decorator';
import { UserService } from '../../authority/service/user-service';
import * as jwt from 'jsonwebtoken';
import { CommonException } from '../../../basic/exception/common-exception';
/**
* 系统用户
*/
@Provide()
export class LoginService {
@Inject()
userService: UserService;
@Config('biz.jwt')
private jwt: any;
/**
* login
*/
async login(user) {
console.assert(user.username != null, '用户名不能为空');
const info = await this.userService.findOne({ username: user.username });
if (info == null) {
throw new CommonException('用户名或密码错误');
}
const right = this.userService.checkPassword(user.password, info.password);
if (!right) {
throw new CommonException('用户名或密码错误');
}
return this.generateToken(info);
}
/**
* 生成token
* @param user 用户对象
*/
async generateToken(user) {
const tokenInfo = {
username: user.username,
id: user.id,
};
const expire = this.jwt.expire;
const token = jwt.sign(tokenInfo, this.jwt.secret, {
expiresIn: expire,
});
return {
token,
expire,
};
}
}