refactor: users plugin
This commit is contained in:
parent
336e0b17b8
commit
f300fd6ae9
@ -3,14 +3,13 @@
|
|||||||
"version": "0.4.0-alpha.7",
|
"version": "0.4.0-alpha.7",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
|
||||||
"@nocobase/actions": "^0.4.0-alpha.7",
|
|
||||||
"@nocobase/server": "^0.4.0-alpha.7"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nocobase/database": "^0.4.0-alpha.7",
|
"@nocobase/database": "^0.4.0-alpha.7",
|
||||||
"@nocobase/resourcer": "^0.4.0-alpha.7",
|
"@nocobase/resourcer": "^0.4.0-alpha.7",
|
||||||
"crypto-random-string": "^3.3.0"
|
"crypto-random-string": "^3.3.0"
|
||||||
},
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@nocobase/test": "^0.4.0-alpha.7"
|
||||||
|
},
|
||||||
"gitHead": "f0b335ac30f29f25c95d7d137655fa64d8d67f1e"
|
"gitHead": "f0b335ac30f29f25c95d7d137655fa64d8d67f1e"
|
||||||
}
|
}
|
||||||
|
@ -1,111 +1,96 @@
|
|||||||
import { getApp, getAgent } from '.';
|
// @ts-nocheck
|
||||||
|
import Database from '@nocobase/database';
|
||||||
|
import { mockServer, MockServer } from '@nocobase/test';
|
||||||
|
|
||||||
describe('user fields', () => {
|
describe('user fields', () => {
|
||||||
let app;
|
let api: MockServer;
|
||||||
let agent;
|
let db: Database;
|
||||||
let db;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
app = await getApp();
|
api = mockServer();
|
||||||
agent = getAgent(app);
|
api.registerPlugin('users', require('../server').default);
|
||||||
db = app.database;
|
await api.loadPlugins();
|
||||||
|
db = api.database;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
await db.sync();
|
|
||||||
await db.close();
|
await db.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('model definition', () => {
|
describe('model definition', () => {
|
||||||
it('add model without createdBy/updatedBy field', async () => {
|
it('createdBy=false/updatedBy=false', async () => {
|
||||||
const Collection = db.getModel('collections');
|
db.table({
|
||||||
await Collection.create({ name: 'posts', internal: true });
|
name: 'posts',
|
||||||
|
createdBy: false,
|
||||||
|
updatedBy: false,
|
||||||
|
});
|
||||||
|
await db.sync();
|
||||||
const Post = db.getModel('posts');
|
const Post = db.getModel('posts');
|
||||||
|
|
||||||
const post = await Post.create();
|
const post = await Post.create();
|
||||||
expect(post.created_by_id).toBeUndefined();
|
expect(post.created_by_id).toBeUndefined();
|
||||||
expect(post.updated_by_id).toBeUndefined();
|
expect(post.updated_by_id).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('add model without createdBy/updatedBy field', async () => {
|
it('without createdBy/updatedBy', async () => {
|
||||||
const Collection = db.getModel('collections');
|
db.table({
|
||||||
await Collection.create({ name: 'posts' });
|
|
||||||
const Post = db.getModel('posts');
|
|
||||||
|
|
||||||
const post = await Post.create();
|
|
||||||
expect(post.created_by_id).toBeDefined();
|
|
||||||
expect(post.updated_by_id).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('add model with named createdBy/updatedBy field', async () => {
|
|
||||||
const Collection = db.getModel('collections');
|
|
||||||
await Collection.create({ name: 'posts', createdBy: 'author', updatedBy: 'editor' });
|
|
||||||
const Post = db.getModel('posts');
|
|
||||||
|
|
||||||
const post = await Post.create();
|
|
||||||
expect(post.author_id).toBeDefined();
|
|
||||||
expect(post.editor_id).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('add model with named createdBy/updatedBy field and target', async () => {
|
|
||||||
const Collection = db.getModel('collections');
|
|
||||||
await Collection.create({
|
|
||||||
name: 'posts',
|
name: 'posts',
|
||||||
createdBy: { name: 'author', target: 'users' },
|
|
||||||
updatedBy: { name: 'editor', target: 'users' }
|
|
||||||
});
|
});
|
||||||
|
await db.sync();
|
||||||
const Post = db.getModel('posts');
|
const Post = db.getModel('posts');
|
||||||
|
|
||||||
const post = await Post.create();
|
|
||||||
expect(post.author_id).toBeDefined();
|
|
||||||
expect(post.editor_id).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('add model with boolean createdBy/updatedBy field', async () => {
|
|
||||||
const Collection = db.getModel('collections');
|
|
||||||
await Collection.create({ name: 'posts', createdBy: true, updatedBy: true });
|
|
||||||
const Post = db.getModel('posts');
|
|
||||||
|
|
||||||
const post = await Post.create();
|
const post = await Post.create();
|
||||||
expect(post.created_by_id).toBeDefined();
|
expect(post.created_by_id).toBeDefined();
|
||||||
expect(post.updated_by_id).toBeDefined();
|
expect(post.updated_by_id).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO(bug): 重复添加字段不能与 fields 表同步,应做到同步
|
it('updatedBy=author/updatedBy=editor', async () => {
|
||||||
it('add model and then add createdBy/updatedBy field', async () => {
|
db.table({
|
||||||
const Collection = db.getModel('collections');
|
name: 'posts',
|
||||||
const collection = await Collection.import({
|
createdBy: 'author',
|
||||||
|
updatedBy: 'editor',
|
||||||
|
});
|
||||||
|
await db.sync();
|
||||||
|
const Post = db.getModel('posts');
|
||||||
|
const post = await Post.create();
|
||||||
|
expect(post.author_id).toBeDefined();
|
||||||
|
expect(post.editor_id).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('createdBy=true/updatedBy=true', async () => {
|
||||||
|
db.table({
|
||||||
name: 'posts',
|
name: 'posts',
|
||||||
createdBy: true,
|
createdBy: true,
|
||||||
updatedBy: true,
|
updatedBy: true,
|
||||||
|
});
|
||||||
|
await db.sync();
|
||||||
|
const Post = db.getModel('posts');
|
||||||
|
const post = await Post.create();
|
||||||
|
expect(post.created_by_id).toBeDefined();
|
||||||
|
expect(post.updated_by_id).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('add model and then add createdBy/updatedBy field', async () => {
|
||||||
|
db.table({
|
||||||
|
name: 'posts',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
interface: 'createdBy',
|
|
||||||
title: '创建人1',
|
|
||||||
type: 'createdBy',
|
type: 'createdBy',
|
||||||
name: 'createdBy1',
|
name: 'createdBy1',
|
||||||
target: 'users',
|
target: 'users',
|
||||||
foreignKey: 'created_by_id',
|
foreignKey: 'created_by_id',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
interface: 'updatedBy',
|
|
||||||
title: '更新人1',
|
|
||||||
type: 'updatedBy',
|
type: 'updatedBy',
|
||||||
name: 'updatedBy1',
|
name: 'updatedBy1',
|
||||||
target: 'users',
|
target: 'users',
|
||||||
foreignKey: 'updated_by_id',
|
foreignKey: 'updated_by_id',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
interface: 'createdBy',
|
|
||||||
title: '创建人2',
|
|
||||||
type: 'createdBy',
|
type: 'createdBy',
|
||||||
name: 'createdBy2',
|
name: 'createdBy2',
|
||||||
target: 'users',
|
target: 'users',
|
||||||
foreignKey: 'created_by_id',
|
foreignKey: 'created_by_id',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
interface: 'updatedBy',
|
|
||||||
title: '更新人2',
|
|
||||||
type: 'updatedBy',
|
type: 'updatedBy',
|
||||||
name: 'updatedBy2',
|
name: 'updatedBy2',
|
||||||
target: 'users',
|
target: 'users',
|
||||||
@ -113,8 +98,8 @@ describe('user fields', () => {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
const table = db.getTable('posts');
|
|
||||||
// console.log(table.getFields());
|
await db.sync();
|
||||||
|
|
||||||
const User = db.getModel('users');
|
const User = db.getModel('users');
|
||||||
const Post = db.getModel('posts');
|
const Post = db.getModel('posts');
|
||||||
@ -150,41 +135,13 @@ describe('user fields', () => {
|
|||||||
expect(post2.createdBy2.id).toBe(user1.id);
|
expect(post2.createdBy2.id).toBe(user1.id);
|
||||||
expect(post2.updatedBy1.id).toBe(user2.id);
|
expect(post2.updatedBy1.id).toBe(user2.id);
|
||||||
expect(post2.updatedBy2.id).toBe(user2.id);
|
expect(post2.updatedBy2.id).toBe(user2.id);
|
||||||
|
|
||||||
|
|
||||||
// const Collection = db.getModel('collections');
|
|
||||||
// const collection = await Collection.create({
|
|
||||||
// name: 'posts'
|
|
||||||
// });
|
|
||||||
// const createdByField = await collection.createField({ type: 'createdBy', name: 'author', target: 'users' });
|
|
||||||
// const updatedByField = await collection.createField({ type: 'updatedBy', name: 'editor', target: 'users' });
|
|
||||||
|
|
||||||
// const postTable = db.getTable('posts');
|
|
||||||
// const Post = db.getModel('posts');
|
|
||||||
|
|
||||||
// // create data should contain added fields
|
|
||||||
// const post = await Post.create();
|
|
||||||
// expect(post[postTable.getField(createdByField.get('name')).options.foreignKey]).toBeDefined();
|
|
||||||
// expect(post[postTable.getField(updatedByField.get('name')).options.foreignKey]).toBeDefined();
|
|
||||||
|
|
||||||
// // add same type field twice should get same field
|
|
||||||
// const createdByField2 = await collection.createField({ type: 'createdBy', target: 'users' });
|
|
||||||
// expect(createdByField2.get('name')).toBe(createdByField.get('name'));
|
|
||||||
|
|
||||||
// // add same type field twice with a new name should get same field name as before
|
|
||||||
// const updatedByField2 = await collection.createField({ type: 'updatedBy', name: 'proofreader', target: 'users' });
|
|
||||||
// expect(updatedByField2.get('name')).toBe(updatedByField.get('name'));
|
|
||||||
|
|
||||||
// // delete field data should not really remove the column in table
|
|
||||||
// await createdByField2.destroy();
|
|
||||||
// expect(postTable.getField('author')).toBeDefined();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('createdBy field', () => {
|
describe('createdBy field', () => {
|
||||||
it('create data with createdBy/updatedBy field', async () => {
|
it('create data with createdBy/updatedBy field', async () => {
|
||||||
const Collection = db.getModel('collections');
|
db.table({ name: 'posts', createdBy: true, updatedBy: true });
|
||||||
await Collection.create({ name: 'posts', createdBy: true, updatedBy: true });
|
await db.sync();
|
||||||
const User = db.getModel('users');
|
const User = db.getModel('users');
|
||||||
const currentUser = await User.create();
|
const currentUser = await User.create();
|
||||||
const user2 = await User.create();
|
const user2 = await User.create();
|
||||||
@ -193,20 +150,21 @@ describe('user fields', () => {
|
|||||||
const postWithoutUser = await Post.create();
|
const postWithoutUser = await Post.create();
|
||||||
expect(postWithoutUser.created_by_id).toBe(null);
|
expect(postWithoutUser.created_by_id).toBe(null);
|
||||||
expect(postWithoutUser.updated_by_id).toBe(null);
|
expect(postWithoutUser.updated_by_id).toBe(null);
|
||||||
|
// @ts-ignore
|
||||||
const postWithUser = await Post.create({}, { context: { state: { currentUser } } });
|
const postWithUser = await Post.create({}, { context: { state: { currentUser } } });
|
||||||
expect(postWithUser.created_by_id).toBe(currentUser.id);
|
expect(postWithUser.created_by_id).toBe(currentUser.id);
|
||||||
expect(postWithUser.updated_by_id).toBe(currentUser.id);
|
expect(postWithUser.updated_by_id).toBe(currentUser.id);
|
||||||
|
|
||||||
// 更新数据 createdBy 数据不变
|
// 更新数据 createdBy 数据不变
|
||||||
|
// @ts-ignore
|
||||||
await postWithUser.update({ title: 'title1' }, { context: { state: { currentUser: user2 } } });
|
await postWithUser.update({ title: 'title1' }, { context: { state: { currentUser: user2 } } });
|
||||||
expect(postWithUser.created_by_id).toBe(currentUser.id);
|
expect(postWithUser.created_by_id).toBe(currentUser.id);
|
||||||
expect(postWithUser.updated_by_id).toBe(user2.id);
|
expect(postWithUser.updated_by_id).toBe(user2.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('create data with value of createdBy/updatedBy field', async () => {
|
it('create data with value of createdBy/updatedBy field', async () => {
|
||||||
const Collection = db.getModel('collections');
|
db.table({ name: 'posts', createdBy: true, updatedBy: true });
|
||||||
await Collection.create({ name: 'posts', createdBy: true, updatedBy: true });
|
await db.sync();
|
||||||
const User = db.getModel('users');
|
const User = db.getModel('users');
|
||||||
const user1 = await User.create();
|
const user1 = await User.create();
|
||||||
const user2 = await User.create();
|
const user2 = await User.create();
|
||||||
@ -215,6 +173,7 @@ describe('user fields', () => {
|
|||||||
const post = await Post.create({
|
const post = await Post.create({
|
||||||
created_by_id: user1.id,
|
created_by_id: user1.id,
|
||||||
updated_by_id: user1.id,
|
updated_by_id: user1.id,
|
||||||
|
// @ts-ignore
|
||||||
}, { context: { state: { currentUser: user2 } } });
|
}, { context: { state: { currentUser: user2 } } });
|
||||||
expect(post.created_by_id).toBe(user1.id);
|
expect(post.created_by_id).toBe(user1.id);
|
||||||
expect(post.updated_by_id).toBe(user1.id);
|
expect(post.updated_by_id).toBe(user1.id);
|
||||||
@ -223,9 +182,9 @@ describe('user fields', () => {
|
|||||||
|
|
||||||
describe('updatedBy field', () => {
|
describe('updatedBy field', () => {
|
||||||
it('update data ', async () => {
|
it('update data ', async () => {
|
||||||
const Collection = db.getModel('collections');
|
db.table({
|
||||||
await Collection.create({
|
|
||||||
name: 'posts',
|
name: 'posts',
|
||||||
|
createdBy: false,
|
||||||
updatedBy: true,
|
updatedBy: true,
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
@ -234,20 +193,20 @@ describe('user fields', () => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
await db.sync();
|
||||||
const User = db.getModel('users');
|
const User = db.getModel('users');
|
||||||
const currentUser = await User.create();
|
const currentUser = await User.create();
|
||||||
const Post = db.getModel('posts');
|
const Post = db.getModel('posts');
|
||||||
|
|
||||||
const post = await Post.create();
|
const post = await Post.create();
|
||||||
expect(post.updated_by_id).toBe(null);
|
expect(post.updated_by_id).toBe(null);
|
||||||
|
// @ts-ignore
|
||||||
await post.update({ title: 'title' }, { context: { state: { currentUser } } })
|
await post.update({ title: 'title' }, { context: { state: { currentUser } } })
|
||||||
expect(post.updated_by_id).toBe(currentUser.id);
|
expect(post.updated_by_id).toBe(currentUser.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('update data by different user', async () => {
|
it('update data by different user', async () => {
|
||||||
const Collection = db.getModel('collections');
|
db.table({
|
||||||
await Collection.create({
|
|
||||||
name: 'posts',
|
name: 'posts',
|
||||||
updatedBy: true,
|
updatedBy: true,
|
||||||
fields: [
|
fields: [
|
||||||
@ -257,6 +216,7 @@ describe('user fields', () => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
await db.sync();
|
||||||
const User = db.getModel('users');
|
const User = db.getModel('users');
|
||||||
const user1 = await User.create();
|
const user1 = await User.create();
|
||||||
const user2 = await User.create();
|
const user2 = await User.create();
|
||||||
@ -285,9 +245,10 @@ describe('user fields', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('bulkUpdate', async () => {
|
it('bulkUpdate', async () => {
|
||||||
const Collection = db.getModel('collections');
|
db.table({
|
||||||
const postCollection = await Collection.create({ name: 'posts', createdBy: false, updatedBy: true });
|
name: 'posts',
|
||||||
await postCollection.updateAssociations({
|
createdBy: false,
|
||||||
|
updatedBy: true,
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
type: 'string',
|
type: 'string',
|
||||||
@ -295,6 +256,7 @@ describe('user fields', () => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
await db.sync();
|
||||||
const User = db.getModel('users');
|
const User = db.getModel('users');
|
||||||
const user1 = await User.create();
|
const user1 = await User.create();
|
||||||
const user2 = await User.create();
|
const user2 = await User.create();
|
||||||
|
@ -1,138 +0,0 @@
|
|||||||
import path from 'path';
|
|
||||||
import qs from 'qs';
|
|
||||||
import supertest from 'supertest';
|
|
||||||
import bodyParser from 'koa-bodyparser';
|
|
||||||
import { Dialect } from 'sequelize';
|
|
||||||
import Database from '@nocobase/database';
|
|
||||||
import { actions, middlewares } from '@nocobase/actions';
|
|
||||||
import { Application, middleware } from '../../../server/src';
|
|
||||||
import plugin from '../server';
|
|
||||||
|
|
||||||
function getTestKey() {
|
|
||||||
const { id } = require.main;
|
|
||||||
const key = id
|
|
||||||
.replace(`${process.env.PWD}/packages`, '')
|
|
||||||
.replace(/src\/__tests__/g, '')
|
|
||||||
.replace('.test.ts', '')
|
|
||||||
.replace(/[^\w]/g, '_')
|
|
||||||
.replace(/_+/g, '_');
|
|
||||||
return key
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
username: process.env.DB_USER,
|
|
||||||
password: process.env.DB_PASSWORD,
|
|
||||||
database: process.env.DB_DATABASE,
|
|
||||||
host: process.env.DB_HOST,
|
|
||||||
port: Number.parseInt(process.env.DB_PORT, 10),
|
|
||||||
dialect: process.env.DB_DIALECT as Dialect,
|
|
||||||
define: {
|
|
||||||
hooks: {
|
|
||||||
beforeCreate(model, options) {
|
|
||||||
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
logging: process.env.DB_LOG_SQL === 'on',
|
|
||||||
sync: {
|
|
||||||
force: true,
|
|
||||||
alter: {
|
|
||||||
drop: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function getApp() {
|
|
||||||
const app = new Application({
|
|
||||||
database: {
|
|
||||||
...config,
|
|
||||||
hooks: {
|
|
||||||
beforeDefine(columns, model) {
|
|
||||||
model.tableName = `${getTestKey()}_${model.tableName || model.name.plural}`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
resourcer: {
|
|
||||||
prefix: '/api',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
app.resourcer.use(middlewares.associated);
|
|
||||||
app.resourcer.registerActionHandlers({ ...actions.associate, ...actions.common });
|
|
||||||
app.registerPlugin('collections', [path.resolve(__dirname, '../../../plugin-collections')]);
|
|
||||||
app.registerPlugin('users', [plugin]);
|
|
||||||
await app.loadPlugins();
|
|
||||||
await app.database.sync();
|
|
||||||
app.use(async (ctx, next) => {
|
|
||||||
ctx.db = app.database;
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
app.use(bodyParser());
|
|
||||||
app.use(middleware({
|
|
||||||
resourcer: app.resourcer,
|
|
||||||
database: app.database,
|
|
||||||
}));
|
|
||||||
return app;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ActionParams {
|
|
||||||
resourceKey?: string | number;
|
|
||||||
// resourceName?: string;
|
|
||||||
// associatedName?: string;
|
|
||||||
associatedKey?: string | number;
|
|
||||||
fields?: any;
|
|
||||||
filter?: any;
|
|
||||||
values?: any;
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Handler {
|
|
||||||
get: (params?: ActionParams) => Promise<supertest.Response>;
|
|
||||||
list: (params?: ActionParams) => Promise<supertest.Response>;
|
|
||||||
create: (params?: ActionParams) => Promise<supertest.Response>;
|
|
||||||
update: (params?: ActionParams) => Promise<supertest.Response>;
|
|
||||||
destroy: (params?: ActionParams) => Promise<supertest.Response>;
|
|
||||||
[name: string]: (params?: ActionParams) => Promise<supertest.Response>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Agent {
|
|
||||||
resource: (name: string) => Handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getAgent(app: Application): Agent {
|
|
||||||
const agent = supertest.agent(app.callback());
|
|
||||||
return {
|
|
||||||
resource(name: string): any {
|
|
||||||
return new Proxy({}, {
|
|
||||||
get(target, method, receiver) {
|
|
||||||
return (params: ActionParams = {}) => {
|
|
||||||
const { associatedKey, resourceKey, values = {}, ...restParams } = params;
|
|
||||||
let url = `/api/${name}`;
|
|
||||||
if (associatedKey) {
|
|
||||||
url = `/api/${name.split('.').join(`/${associatedKey}/`)}`;
|
|
||||||
}
|
|
||||||
url += `:${method as string}`;
|
|
||||||
if (resourceKey) {
|
|
||||||
url += `/${resourceKey}`;
|
|
||||||
}
|
|
||||||
if (['list', 'get'].indexOf(method as string) !== -1) {
|
|
||||||
return agent.get(`${url}?${qs.stringify(restParams)}`);
|
|
||||||
} else {
|
|
||||||
return agent.post(`${url}?${qs.stringify(restParams)}`).send(values);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getDatabase() {
|
|
||||||
return new Database({
|
|
||||||
...config,
|
|
||||||
hooks: {
|
|
||||||
beforeDefine(columns, model) {
|
|
||||||
model.tableName = `${getTestKey()}_${model.tableName || model.name.plural}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,8 +1,8 @@
|
|||||||
import { actions } from '@nocobase/actions';
|
import { Context, Next } from '@nocobase/actions';
|
||||||
import { PASSWORD } from '@nocobase/database';
|
import { PASSWORD } from '@nocobase/database';
|
||||||
import cryptoRandomString from 'crypto-random-string';
|
import cryptoRandomString from 'crypto-random-string';
|
||||||
|
|
||||||
export async function check(ctx: actions.Context, next: actions.Next) {
|
export async function check(ctx: Context, next: Next) {
|
||||||
if (ctx.state.currentUser) {
|
if (ctx.state.currentUser) {
|
||||||
const user = ctx.state.currentUser.toJSON();
|
const user = ctx.state.currentUser.toJSON();
|
||||||
delete user.password;
|
delete user.password;
|
||||||
@ -13,7 +13,7 @@ export async function check(ctx: actions.Context, next: actions.Next) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function login(ctx: actions.Context, next: actions.Next) {
|
export async function login(ctx: Context, next: Next) {
|
||||||
const { uniqueField = 'email', values } = ctx.action.params;
|
const { uniqueField = 'email', values } = ctx.action.params;
|
||||||
// console.log(values);
|
// console.log(values);
|
||||||
if (!values[uniqueField]) {
|
if (!values[uniqueField]) {
|
||||||
@ -42,12 +42,12 @@ export async function login(ctx: actions.Context, next: actions.Next) {
|
|||||||
await next();
|
await next();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function logout(ctx: actions.Context, next: actions.Next) {
|
export async function logout(ctx: Context, next: Next) {
|
||||||
ctx.body = {};
|
ctx.body = {};
|
||||||
await next();
|
await next();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function register(ctx: actions.Context, next: actions.Next) {
|
export async function register(ctx: Context, next: Next) {
|
||||||
const User = ctx.db.getModel('users');
|
const User = ctx.db.getModel('users');
|
||||||
const { values } = ctx.action.params;
|
const { values } = ctx.action.params;
|
||||||
try {
|
try {
|
||||||
@ -66,7 +66,7 @@ export async function register(ctx: actions.Context, next: actions.Next) {
|
|||||||
await next();
|
await next();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function lostpassword(ctx: actions.Context, next: actions.Next) {
|
export async function lostpassword(ctx: Context, next: Next) {
|
||||||
const { values: { email } } = ctx.action.params;
|
const { values: { email } } = ctx.action.params;
|
||||||
if (!email) {
|
if (!email) {
|
||||||
ctx.throw(401, '请填写邮箱账号');
|
ctx.throw(401, '请填写邮箱账号');
|
||||||
@ -86,7 +86,7 @@ export async function lostpassword(ctx: actions.Context, next: actions.Next) {
|
|||||||
await next();
|
await next();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function resetpassword(ctx: actions.Context, next: actions.Next) {
|
export async function resetpassword(ctx: Context, next: Next) {
|
||||||
const { values: { email, password, reset_token } } = ctx.action.params;
|
const { values: { email, password, reset_token } } = ctx.action.params;
|
||||||
const User = ctx.db.getModel('users');
|
const User = ctx.db.getModel('users');
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
@ -106,7 +106,7 @@ export async function resetpassword(ctx: actions.Context, next: actions.Next) {
|
|||||||
await next();
|
await next();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getUserByResetToken(ctx: actions.Context, next: actions.Next) {
|
export async function getUserByResetToken(ctx: Context, next: Next) {
|
||||||
const { token } = ctx.action.params;
|
const { token } = ctx.action.params;
|
||||||
const User = ctx.db.getModel('users');
|
const User = ctx.db.getModel('users');
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
@ -121,7 +121,7 @@ export async function getUserByResetToken(ctx: actions.Context, next: actions.Ne
|
|||||||
await next();
|
await next();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateProfile(ctx: actions.Context, next: actions.Next) {
|
export async function updateProfile(ctx: Context, next: Next) {
|
||||||
const { values } = ctx.action.params;
|
const { values } = ctx.action.params;
|
||||||
if (!ctx.state.currentUser) {
|
if (!ctx.state.currentUser) {
|
||||||
ctx.throw(401, 'Unauthorized');
|
ctx.throw(401, 'Unauthorized');
|
||||||
|
@ -15,10 +15,14 @@ export default class CreatedBy extends BELONGSTO {
|
|||||||
|
|
||||||
constructor({ type, ...options }: CreatedByOptions, context: FieldContext) {
|
constructor({ type, ...options }: CreatedByOptions, context: FieldContext) {
|
||||||
super({ ...options, type: 'belongsTo' } as BelongsToOptions, context);
|
super({ ...options, type: 'belongsTo' } as BelongsToOptions, context);
|
||||||
const Model = context.sourceTable.getModel();
|
// const Model = context.sourceTable.getModel();
|
||||||
// TODO(feature): 可考虑策略模式,以在需要时对外提供接口
|
// TODO(feature): 可考虑策略模式,以在需要时对外提供接口
|
||||||
Model.addHook('beforeCreate', setUserValue.bind(this));
|
// Model.addHook('beforeCreate', setUserValue.bind(this));
|
||||||
Model.addHook('beforeBulkCreate', CreatedBy.beforeBulkCreateHook.bind(this));
|
// Model.addHook('beforeBulkCreate', CreatedBy.beforeBulkCreateHook.bind(this));
|
||||||
|
const { sourceTable, database } = context;
|
||||||
|
const name = sourceTable.getName();
|
||||||
|
database.on(`${name}.beforeCreate`, setUserValue.bind(this));
|
||||||
|
database.on(`${name}.beforeBulkCreate`, CreatedBy.beforeBulkCreateHook.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getDataType(): Function {
|
public getDataType(): Function {
|
||||||
|
@ -27,13 +27,18 @@ export default class UpdatedBy extends BELONGSTO {
|
|||||||
|
|
||||||
constructor({ type, ...options }: UpdatedByOptions, context: FieldContext) {
|
constructor({ type, ...options }: UpdatedByOptions, context: FieldContext) {
|
||||||
super({ ...options, type: 'belongsTo' } as BelongsToOptions, context);
|
super({ ...options, type: 'belongsTo' } as BelongsToOptions, context);
|
||||||
const Model = context.sourceTable.getModel();
|
// const Model = context.sourceTable.getModel();
|
||||||
// TODO(feature): 可考虑策略模式,以在需要时对外提供接口
|
// // TODO(feature): 可考虑策略模式,以在需要时对外提供接口
|
||||||
Model.addHook('beforeCreate', setUserValue.bind(this));
|
// Model.addHook('beforeCreate', setUserValue.bind(this));
|
||||||
Model.addHook('beforeBulkCreate', UpdatedBy.beforeBulkCreateHook.bind(this));
|
// Model.addHook('beforeBulkCreate', UpdatedBy.beforeBulkCreateHook.bind(this));
|
||||||
|
// Model.addHook('beforeUpdate', setUserValue.bind(this));
|
||||||
Model.addHook('beforeUpdate', setUserValue.bind(this));
|
// Model.addHook('beforeBulkUpdate', UpdatedBy.beforeBulkUpdateHook.bind(this));
|
||||||
Model.addHook('beforeBulkUpdate', UpdatedBy.beforeBulkUpdateHook.bind(this));
|
const { sourceTable, database } = context;
|
||||||
|
const name = sourceTable.getName();
|
||||||
|
database.on(`${name}.beforeCreate`, setUserValue.bind(this));
|
||||||
|
database.on(`${name}.beforeBulkCreate`, UpdatedBy.beforeBulkCreateHook.bind(this));
|
||||||
|
database.on(`${name}.beforeUpdate`, setUserValue.bind(this));
|
||||||
|
database.on(`${name}.beforeBulkUpdate`, UpdatedBy.beforeBulkUpdateHook.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getDataType(): Function {
|
public getDataType(): Function {
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
export function makeOptions(type: string, options: any) {
|
|
||||||
if (!options) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let name = type;
|
|
||||||
let target = 'users';
|
|
||||||
switch (typeof options) {
|
|
||||||
case 'string':
|
|
||||||
name = options;
|
|
||||||
break;
|
|
||||||
// 今后支持多账号体系时可以扩展配置
|
|
||||||
case 'object':
|
|
||||||
name = options.name || name;
|
|
||||||
target = options.target || target;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
type,
|
|
||||||
name,
|
|
||||||
target
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function (table) {
|
|
||||||
const { createdBy, updatedBy } = table.getOptions();
|
|
||||||
const fieldsToMake = { createdBy, updatedBy };
|
|
||||||
Object.keys(fieldsToMake)
|
|
||||||
.filter(type => Boolean(fieldsToMake[type]))
|
|
||||||
.map(type => table.addField(makeOptions(type, fieldsToMake[type])));
|
|
||||||
}
|
|
||||||
|
|
||||||
// export default async function(model, options) {
|
|
||||||
// const { database } = model;
|
|
||||||
// const tableName = model.get('name') as string;
|
|
||||||
// const table = database.getTable(tableName);
|
|
||||||
// const { createdBy, updatedBy } = table.getOptions();
|
|
||||||
// const fieldsToMake = { createdBy, updatedBy };
|
|
||||||
// const addedFields = Object.keys(fieldsToMake)
|
|
||||||
// .filter(type => Boolean(fieldsToMake[type]))
|
|
||||||
// .map(type => table.addField(makeOptions(type, fieldsToMake[type])));
|
|
||||||
|
|
||||||
// if (addedFields.length) {
|
|
||||||
// await table.sync({
|
|
||||||
// force: false,
|
|
||||||
// alter: {
|
|
||||||
// drop: false,
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
@ -1,18 +0,0 @@
|
|||||||
import { Model, getDataTypeKey, getField } from '@nocobase/database';
|
|
||||||
|
|
||||||
export default async function (model: Model, options) {
|
|
||||||
// const { database } = model;
|
|
||||||
// const { type, target, collection_name } = model.get();
|
|
||||||
// const table = database.getTable(collection_name);
|
|
||||||
// const Type = getField(getDataTypeKey(type));
|
|
||||||
// let Exist;
|
|
||||||
// for (const Field of table.getFields().values()) {
|
|
||||||
// if (Field instanceof Type && Field.options.target === target) {
|
|
||||||
// Exist = Field;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (Exist) {
|
|
||||||
// model.set('name', Exist.options.name);
|
|
||||||
// }
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
import Database from '@nocobase/database';
|
|
||||||
import collectionsAfterCreate from './collection-after-create';
|
|
||||||
import fieldsBeforeCreate from './fields-before-create';
|
|
||||||
|
|
||||||
export default function () {
|
|
||||||
const database: Database = this.database;
|
|
||||||
// TODO(feature): 应该通过新的插件机制暴露接口,而不是直接访问其他插件的底层代码
|
|
||||||
database.getModel('collections').addHook('afterCreate', collectionsAfterCreate);
|
|
||||||
|
|
||||||
// 由于创建字段不是同时完成的,可能要在不同的 hook 里处理才行
|
|
||||||
database.getModel('fields').addHook('beforeCreate', fieldsBeforeCreate);
|
|
||||||
}
|
|
@ -1,12 +1,8 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import Database, { registerFields, Table } from '@nocobase/database';
|
||||||
import Database, { registerFields } from '@nocobase/database';
|
|
||||||
import Resourcer from '@nocobase/resourcer';
|
import Resourcer from '@nocobase/resourcer';
|
||||||
|
|
||||||
import * as fields from './fields';
|
import * as fields from './fields';
|
||||||
// import hooks from './hooks';
|
|
||||||
import * as usersActions from './actions/users';
|
import * as usersActions from './actions/users';
|
||||||
import { makeOptions } from './hooks/collection-after-create';
|
|
||||||
import * as middlewares from './middlewares';
|
import * as middlewares from './middlewares';
|
||||||
|
|
||||||
export default async function (options = {}) {
|
export default async function (options = {}) {
|
||||||
@ -15,21 +11,22 @@ export default async function (options = {}) {
|
|||||||
|
|
||||||
registerFields(fields);
|
registerFields(fields);
|
||||||
|
|
||||||
database.addHook('afterTableInit', (table) => {
|
database.on('afterTableInit', (table: Table) => {
|
||||||
let { createdBy, updatedBy, internal } = table.getOptions();
|
let { createdBy, updatedBy } = table.getOptions();
|
||||||
// 非内置表,默认创建 createdBy 和 updatedBy
|
if (createdBy !== false) {
|
||||||
if (!internal) {
|
table.addField({
|
||||||
if (typeof createdBy === 'undefined') {
|
type: 'createdBy',
|
||||||
createdBy = true;
|
name: typeof createdBy === 'string' ? createdBy : 'createdBy',
|
||||||
|
target: 'users',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (typeof updatedBy === 'undefined') {
|
if (updatedBy !== false) {
|
||||||
updatedBy = true;
|
table.addField({
|
||||||
|
type: 'updatedBy',
|
||||||
|
name: typeof updatedBy === 'string' ? updatedBy : 'updatedBy',
|
||||||
|
target: 'users',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
const fieldsToMake = { createdBy, updatedBy };
|
|
||||||
Object.keys(fieldsToMake)
|
|
||||||
.filter(type => Boolean(fieldsToMake[type]))
|
|
||||||
.map(type => table.addField(makeOptions(type, fieldsToMake[type])));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
database.import({
|
database.import({
|
||||||
|
@ -17608,7 +17608,7 @@ sequelize-pool@^6.0.0:
|
|||||||
resolved "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz#caaa0c1e324d3c2c3a399fed2c7998970925d668"
|
resolved "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz#caaa0c1e324d3c2c3a399fed2c7998970925d668"
|
||||||
integrity sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg==
|
integrity sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg==
|
||||||
|
|
||||||
sequelize@^6.3.3, sequelize@^6.3.4:
|
sequelize@^6.3.3:
|
||||||
version "6.6.5"
|
version "6.6.5"
|
||||||
resolved "https://registry.npmjs.org/sequelize/-/sequelize-6.6.5.tgz#6f618e99f3df1fc81f28709e8a3139cec3ef1f0c"
|
resolved "https://registry.npmjs.org/sequelize/-/sequelize-6.6.5.tgz#6f618e99f3df1fc81f28709e8a3139cec3ef1f0c"
|
||||||
integrity sha512-QyRrJrDRiwuiILqTMHUA1yWOPIL12KlfmgZ3hnzQwbMvp2vJ6fzu9bYJQB+qPMosck4mBUggY4Cjoc6Et8FBIQ==
|
integrity sha512-QyRrJrDRiwuiILqTMHUA1yWOPIL12KlfmgZ3hnzQwbMvp2vJ6fzu9bYJQB+qPMosck4mBUggY4Cjoc6Et8FBIQ==
|
||||||
|
Loading…
Reference in New Issue
Block a user