From 962d89ff29b552c6f275ff97ec1074cd42e1d37a Mon Sep 17 00:00:00 2001 From: xion Date: Sat, 28 Sep 2024 16:43:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=94=A8=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 9 +- pnpm-lock.yaml | 77 +++++++++++------ src/models/code.ts | 2 +- src/models/user.ts | 78 +++++++++++++++--- src/route.ts | 11 ++- src/routes/container/models/index.ts | 3 + src/routes/index.ts | 2 + src/routes/page/models/index.ts | 5 ++ src/routes/resource/models/index.ts | 3 + src/routes/user/index.ts | 1 + src/routes/user/list.ts | 119 +++++++++++++++++++++++++++ src/scripts/add-uid.ts | 35 ++++++++ 12 files changed, 303 insertions(+), 42 deletions(-) create mode 100644 src/routes/user/index.ts create mode 100644 src/routes/user/list.ts create mode 100644 src/scripts/add-uid.ts diff --git a/package.json b/package.json index 2a684b4..96167d2 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "dev:watch": "concurrently -n \"Watch,Dev\" -c \"green,blue\" \"npm run watch\" \"sleep 1 && npm run dev\" ", "build": "cross-env ENV=production webpack --mode=production ", "build:sh": "cross-env webpack --mode=production -c ./webpack.shell.config.cjs", - "deploy": "rsync -avz --delete ./dist/ light:~/apps/codeflow/backend", + "deploy": "rsync -avz --delete ./dist/ --exclude='app.config.json5' light:~/apps/codeflow/backend", "deploy:sh": "", "clean": "rm -rf dist", "reload": "ssh light pm2 restart codeflow", @@ -31,7 +31,8 @@ ], "license": "ISC", "dependencies": { - "@abearxiong/router": "0.0.1-alpha.36", + "@abearxiong/auth": "1.0.0-alpha.5", + "@abearxiong/router": "0.0.1-alpha.38", "@abearxiong/use-config": "^0.0.2", "@babel/core": "^7.25.2", "@babel/preset-env": "^7.25.4", @@ -47,7 +48,7 @@ "lodash-es": "^4.17.21", "minio": "^8.0.1", "nanoid": "^5.0.7", - "neo4j-driver": "^5.24.1", + "neo4j-driver": "^5.25.0", "neode": "^0.4.9", "ollama": "^0.5.9", "pg": "^8.13.0", @@ -62,7 +63,7 @@ "@types/crypto-js": "^4.2.2", "@types/jsonwebtoken": "^9.0.7", "@types/lodash-es": "^4.17.12", - "@types/node": "^22.7.2", + "@types/node": "^22.7.4", "@types/uuid": "^10.0.0", "@types/webpack-env": "^1.18.5", "concurrently": "^9.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2708c31..63a8d45 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,9 +13,12 @@ importers: .: dependencies: + '@abearxiong/auth': + specifier: 1.0.0-alpha.5 + version: 1.0.0-alpha.5(@abearxiong/router@0.0.1-alpha.38) '@abearxiong/router': - specifier: 0.0.1-alpha.36 - version: 0.0.1-alpha.36 + specifier: 0.0.1-alpha.38 + version: 0.0.1-alpha.38 '@abearxiong/use-config': specifier: ^0.0.2 version: 0.0.2 @@ -62,8 +65,8 @@ importers: specifier: ^5.0.7 version: 5.0.7 neo4j-driver: - specifier: ^5.24.1 - version: 5.24.1 + specifier: ^5.25.0 + version: 5.25.0 neode: specifier: ^0.4.9 version: 0.4.9 @@ -102,8 +105,8 @@ importers: specifier: ^4.17.12 version: 4.17.12 '@types/node': - specifier: ^22.7.2 - version: 22.7.2 + specifier: ^22.7.4 + version: 22.7.4 '@types/uuid': specifier: ^10.0.0 version: 10.0.0 @@ -219,9 +222,17 @@ importers: packages: + '@abearxiong/auth@1.0.0-alpha.5': + resolution: {integrity: sha512-/DPlwvWN0zLQ7X3D/zAhtHRTVWP/Odn3lZeyllUzjn8PFV9E5pCVXbLV9fBqmP400icZkG9a3fplSbUrVIIpOA==, tarball: https://npm.pkg.github.com/download/@abearxiong/auth/1.0.0-alpha.5/9d149a4e10bde7fd51b102b00849d75da85dd282} + peerDependencies: + '@abearxiong/router': ^0.0.1-alpha.38 + '@abearxiong/router@0.0.1-alpha.36': resolution: {integrity: sha512-rpxel/upIeJEsRYHXqAOezAooPvXFjuWeA28oB/KClrP8B9WY8grlmHQUkvtsGtXypOCqcYoxZ9Nb9awJlzN5A==, tarball: https://npm.pkg.github.com/download/@abearxiong/router/0.0.1-alpha.36/c4e3c3f88da8e6b1217450ab3713c600efcb5504} + '@abearxiong/router@0.0.1-alpha.38': + resolution: {integrity: sha512-jLYYrZVGx6gVbNX4l39Abt4jIf9LrvIwD/dKHf1/RvVQZFUmHpBbjl8ppC7XTNLKvtBX/zFQa6IUhzy1C9E2Yg==, tarball: https://npm.pkg.github.com/download/@abearxiong/router/0.0.1-alpha.38/80e8d75af11213d20ffbc3d9ffa112cb9add76c9} + '@abearxiong/use-config@0.0.2': resolution: {integrity: sha512-IBOmeP46ykbDlkplFS65UsAHjyPDKnvS2oqbkpLWhbSwDbF5zhBnD4ibsFZKPCyc3lMlPeRqYva4x6puX3E/qQ==, tarball: https://npm.pkg.github.com/download/@abearxiong/use-config/0.0.2/59fbeec8c8e086ec48e55024fe39020b079e6fa5} @@ -1257,6 +1268,9 @@ packages: '@types/node@22.7.2': resolution: {integrity: sha512-866lXSrpGpgyHBZUa2m9YNWqHDjjM0aBTJlNtYaGEw4rqY/dcD7deRVTbBBAJelfA7oaGDbNftXF/TL/A6RgoA==} + '@types/node@22.7.4': + resolution: {integrity: sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==} + '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} @@ -2460,20 +2474,20 @@ packages: neo4j-driver-bolt-connection@4.4.11: resolution: {integrity: sha512-2sCgx3Lpg7fnYAU/kb9wOKY8ResUeur88MhLNUWyINxa+CMP7aB+t70zBcOlJ7hcCf6ghEiz6ZXhd9WikGW9bA==} - neo4j-driver-bolt-connection@5.24.1: - resolution: {integrity: sha512-5xS93jPqpeTh5+62r6fizxQdOMGMpUcuNKTOP4Pn0OPVMM0IMlemJhSUEQf7k1yJmsZNn6InKRBAmPjZm5+2dw==} + neo4j-driver-bolt-connection@5.25.0: + resolution: {integrity: sha512-plQnrqu14rMLX4p/8a5/BjdFKbLihpslsV0+uTe+9sa1iAtelanTsgkPscZuQRW041anGvO0KE/vN7xqbPJaFg==} neo4j-driver-core@4.4.11: resolution: {integrity: sha512-7+7Ue9RNsg5TAwkPvl4/st2ZdktN3qH8A/MYmJkZ6Ait8MuXP8ppTvZ3ugPxbrSOJEwvZYpKqV+FNZ17mOSfcQ==} - neo4j-driver-core@5.24.1: - resolution: {integrity: sha512-nPPAXnEypaE4HloM2x8GggF5YT7e+LpcEuyYt7ELuax25/SH7ZtdkemnH0voAVfqBwQXSWP9CFpPFznDOU6T5A==} + neo4j-driver-core@5.25.0: + resolution: {integrity: sha512-fdPAKlhtosNJw8eDrDZ+Krpgl9Yqe/dTUTVdU7Ud83E3QHl3ILp8n/uN7zyixf5sPI+11t/bqH4Z6vtANwYqPw==} neo4j-driver@4.4.11: resolution: {integrity: sha512-1dhThyuNZt4FIwAlmzsbYNnSn28avjO2TVairuFO3P/aql5iPnwTNGmQJc/MB8BlrzDhOo1+jfAO4pc49XHh1Q==} - neo4j-driver@5.24.1: - resolution: {integrity: sha512-ziTNnesM24liI/fPpykLQtO7Hu4Mq5QxiePwPBSZtmylwzJWs/apLg3RiTioyXAZytKbdmldyUwmJSBnxbjLCw==} + neo4j-driver@5.25.0: + resolution: {integrity: sha512-1CNl5ArQH5nXrH0sJOsrM3/ezra8ivxTeXiBzas1HBizi7zPXhrpnQTSDvFcTW1NV9GOioW8/ei7B59kcVaK3Q==} neode@0.4.9: resolution: {integrity: sha512-3RufLD2cmTXrPpvsgkEAqS3maRjXJ89vjbyYmyqJMJl5uv6gcUa32N6hRwHcqfjWRWUaFKaoGLEJLaOQobs4eA==} @@ -3357,6 +3371,10 @@ packages: snapshots: + '@abearxiong/auth@1.0.0-alpha.5(@abearxiong/router@0.0.1-alpha.38)': + dependencies: + '@abearxiong/router': 0.0.1-alpha.38 + '@abearxiong/router@0.0.1-alpha.36': dependencies: ws: 8.18.0 @@ -3364,6 +3382,13 @@ snapshots: - bufferutil - utf-8-validate + '@abearxiong/router@0.0.1-alpha.38': + dependencies: + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@abearxiong/use-config@0.0.2': {} '@ampproject/remapping@2.3.0': @@ -4467,7 +4492,7 @@ snapshots: '@types/cors@2.8.17': dependencies: - '@types/node': 22.7.2 + '@types/node': 22.7.4 '@types/crypto-js@4.2.2': {} @@ -4483,7 +4508,7 @@ snapshots: '@types/jsonwebtoken@9.0.7': dependencies: - '@types/node': 22.7.2 + '@types/node': 22.7.4 '@types/lodash-es@4.17.12': dependencies: @@ -4495,7 +4520,7 @@ snapshots: '@types/node-fetch@2.6.11': dependencies: - '@types/node': 22.7.2 + '@types/node': 22.7.4 form-data: 4.0.0 '@types/node@18.19.53': @@ -4506,6 +4531,10 @@ snapshots: dependencies: undici-types: 6.19.8 + '@types/node@22.7.4': + dependencies: + undici-types: 6.19.8 + '@types/resolve@1.20.2': {} '@types/retry@0.12.0': {} @@ -5035,7 +5064,7 @@ snapshots: dependencies: '@types/cookie': 0.4.1 '@types/cors': 2.8.17 - '@types/node': 22.7.2 + '@types/node': 22.7.4 accepts: 1.3.8 base64id: 2.0.0 cookie: 0.4.2 @@ -5576,7 +5605,7 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 22.7.2 + '@types/node': 22.7.4 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -5793,15 +5822,15 @@ snapshots: neo4j-driver-core: 4.4.11 string_decoder: 1.3.0 - neo4j-driver-bolt-connection@5.24.1: + neo4j-driver-bolt-connection@5.25.0: dependencies: buffer: 6.0.3 - neo4j-driver-core: 5.24.1 + neo4j-driver-core: 5.25.0 string_decoder: 1.3.0 neo4j-driver-core@4.4.11: {} - neo4j-driver-core@5.24.1: {} + neo4j-driver-core@5.25.0: {} neo4j-driver@4.4.11: dependencies: @@ -5810,10 +5839,10 @@ snapshots: neo4j-driver-core: 4.4.11 rxjs: 6.6.7 - neo4j-driver@5.24.1: + neo4j-driver@5.25.0: dependencies: - neo4j-driver-bolt-connection: 5.24.1 - neo4j-driver-core: 5.24.1 + neo4j-driver-bolt-connection: 5.25.0 + neo4j-driver-core: 5.25.0 rxjs: 7.8.1 neode@0.4.9: @@ -6691,7 +6720,7 @@ snapshots: wkx@0.5.0: dependencies: - '@types/node': 22.7.2 + '@types/node': 22.7.4 wrap-ansi@7.0.0: dependencies: diff --git a/src/models/code.ts b/src/models/code.ts index f673650..dc7ca2a 100644 --- a/src/models/code.ts +++ b/src/models/code.ts @@ -41,7 +41,7 @@ RouterCodeModel.init( type: DataTypes.UUID, primaryKey: true, defaultValue: DataTypes.UUIDV4, - comment: '用户code id', + comment: 'code id', }, path: { type: DataTypes.STRING, diff --git a/src/models/user.ts b/src/models/user.ts index 68ae44a..ea37e92 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -1,24 +1,60 @@ +import { useConfig } from '@abearxiong/use-config'; import { sequelize } from '@/modules/sequelize.ts'; import { DataTypes, Model } from 'sequelize'; +import { createToken, checkToken } from '@abearxiong/auth/token'; +import { cryptPwd } from '@abearxiong/auth'; +import { nanoid } from 'nanoid'; +import { CustomError } from '@abearxiong/router'; + +const config = useConfig<{ tokenSecret: string }>(); export class User extends Model { - declare id: number; - username: string; - password: string; - salt: string; - remark: string; + declare id: string; + declare username: string; + declare password: string; + declare salt: string; + declare needChangePassword: boolean; + declare description: string; + declare data: any; + async createToken() { + const { id, username } = this; + const expireTime = 60 * 60 * 24 * 7; // 7 days + const now = new Date().getTime(); + const token = await createToken({ id, username }, config.tokenSecret); + return { token, expireTime: now + expireTime }; + } + static async verifyToken(token: string) { + return await checkToken(token, config.tokenSecret); + } + static createUser(username: string, password?: string, description?: string) { + const user = User.findOne({ where: { username } }); + if (user) { + throw new CustomError('User already exists'); + } + const salt = nanoid(6); + let needChangePassword = !password; + password = password || '123456'; + const cPassword = cryptPwd(password, salt); + return User.create({ username, password: cPassword, description, salt, needChangePassword }); + } + createPassword(password: string) { + const salt = this.salt; + const cPassword = cryptPwd(password, salt); + this.password = cPassword; + return cPassword; + } } User.init( { id: { - type: DataTypes.INTEGER, - autoIncrement: true, + type: DataTypes.UUID, primaryKey: true, + defaultValue: DataTypes.UUIDV4, }, - username: { type: DataTypes.STRING, allowNull: false, + unique: true, }, password: { type: DataTypes.STRING, @@ -28,28 +64,44 @@ User.init( type: DataTypes.STRING, allowNull: false, }, - remark: { + description: { type: DataTypes.STRING, }, + needChangePassword: { + type: DataTypes.BOOLEAN, + defaultValue: false, + }, + data: { + type: DataTypes.JSON, + defaultValue: {}, + }, }, { sequelize, tableName: 'cf_user', }, ); -// User.sync({ alter: true }); +User.sync({ alter: true, logging: false }) + .then((res) => { + // initializeUser(); + }) + .catch((err) => { + console.error('Sync User error', err); + }); export const initializeUser = async () => { - const w = await User.findOne(); + const w = await User.findAndCountAll(); + console.info('[User count]', w.count); const password = '2e8a305521bba54f49638ed25e46adf3'; //123456 const salt = '123'; const users = [{ username: 'admin' }, { username: 'user' }, { username: 'root' }]; - if (!w) { + if (w.count < 1) { const newUsers = await User.bulkCreate( users.map((user) => { return { ...user, password, + needChangePassword: true, salt, }; }), @@ -57,3 +109,5 @@ export const initializeUser = async () => { console.info('[create new Users]', newUsers); } }; + +// initializeUser(); diff --git a/src/route.ts b/src/route.ts index e2d3f7f..bbe8f74 100644 --- a/src/route.ts +++ b/src/route.ts @@ -1,3 +1,12 @@ import './demo/index.ts'; import './admin/index.ts'; -import './routes/index.ts'; \ No newline at end of file +import './routes/index.ts'; +import { app } from './app.ts'; +import { useConfig } from '@abearxiong/use-config'; +import { createAuthRoute } from '@abearxiong/auth'; +const config = useConfig<{ tokenSecret: string }>(); + +createAuthRoute({ + app, + secret: config.tokenSecret, +}); diff --git a/src/routes/container/models/index.ts b/src/routes/container/models/index.ts index 66bb76b..92bf904 100644 --- a/src/routes/container/models/index.ts +++ b/src/routes/container/models/index.ts @@ -10,6 +10,9 @@ export type ContainerPublish = { }; export type Container = Partial>; +/** + * 用户代码容器 + */ export class ContainerModel extends Model { declare id: string; declare title: string; diff --git a/src/routes/index.ts b/src/routes/index.ts index c440a99..63ec4ff 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -7,3 +7,5 @@ import './resource/index.ts'; import './prompt-graph/index.ts'; import './agent/index.ts'; + +import './user/index.ts'; diff --git a/src/routes/page/models/index.ts b/src/routes/page/models/index.ts index b4faa28..f6bdbd9 100644 --- a/src/routes/page/models/index.ts +++ b/src/routes/page/models/index.ts @@ -18,18 +18,23 @@ type PageNodeData = { [key: string]: any; }; + export interface PageData { edges: any[]; nodes: PageNodeData[]; viewport: any; [key: string]: any; } +/** + * 页面数据 + */ export class PageModel extends Model { declare id: string; declare title: string; declare description: string; declare type: string; declare data: PageData; + declare uid: string; } PageModel.init( { diff --git a/src/routes/resource/models/index.ts b/src/routes/resource/models/index.ts index 3a89a92..42a5b93 100644 --- a/src/routes/resource/models/index.ts +++ b/src/routes/resource/models/index.ts @@ -28,6 +28,9 @@ export type Resource = { uid?: string; }; +/** + * 资源管理 + */ export class ResourceModel extends Model { declare id: string; declare name: string; diff --git a/src/routes/user/index.ts b/src/routes/user/index.ts new file mode 100644 index 0000000..9166f9d --- /dev/null +++ b/src/routes/user/index.ts @@ -0,0 +1 @@ +import './list.ts' \ No newline at end of file diff --git a/src/routes/user/list.ts b/src/routes/user/list.ts new file mode 100644 index 0000000..23ca556 --- /dev/null +++ b/src/routes/user/list.ts @@ -0,0 +1,119 @@ +import { app } from '@/app.ts'; +import { User } from '@/models/user.ts'; +import { CustomError } from '@abearxiong/router'; + +app + .route('user', 'list') + .define(async (ctx) => { + const users = await User.findAll({ + attributes: ['id', 'username', 'description', 'needChangePassword'], + order: [['updatedAt', 'DESC']], + logging: false, + }); + ctx.body = users; + }) + .addTo(app); + +app + .route('user', 'login') + .define(async (ctx) => { + const { username, password } = ctx.query; + const user = await User.findOne({ where: { username } }); + if (!user) { + new CustomError(401, 'User not found'); + } + if (user.password !== password) { + new CustomError(401, 'Password error'); + } + const token = await user.createToken(); + ctx.body = token; + }) + .addTo(app); + +app + .route('user', 'auth') + .define(async (ctx) => { + const { checkToken: token } = ctx.query; + try { + const result = await User.verifyToken(token); + ctx.body = result?.payload || {}; + } catch (e) { + new CustomError(401, 'Token InValid '); + } + }) + .addTo(app); + +app + .route('user', 'updateSelf', { + middleware: ['auth'], + }) + .define(async (ctx) => { + const { username, password, description } = ctx.query; + const state = ctx.state?.tokenUser || {}; + const { id } = state; + const user = await User.findByPk(id); + if (!user) { + throw new CustomError(500, 'user not found'); + } + if (username) { + user.username = username; + } + if (password) { + user.createPassword(password); + } + if (description) { + user.description = description; + } + await user.save(); + ctx.body = { + id: user.id, + username: user.username, + description: user.description, + needChangePassword: user.needChangePassword, + }; + }) + .addTo(app); +app + .route('user', 'update', { + middleware: ['auth'], + }) + .define(async (ctx) => { + const { id, username, password, description } = ctx.query; + const user = await User.findByPk(id); + if (!user) { + throw new CustomError(500, 'user not found'); + } + if (username) { + user.username = username; + } + if (password) { + user.createPassword(password); + } + if (description) { + user.description = description; + } + await user.save(); + ctx.body = { + id: user.id, + username: user.username, + description: user.description, + needChangePassword: user.needChangePassword, + }; + }) + .addTo(app); + +app.route('user', 'add').define(async (ctx) => { + const { username, password, description } = ctx.query; + if (!username) { + throw new CustomError(400, 'username is required'); + } + const user = await User.createUser(username, password, description); + const token = await user.createToken(); + ctx.body = { + id: user.id, + username: user.username, + description: user.description, + needChangePassword: user.needChangePassword, + token, + }; +}); diff --git a/src/scripts/add-uid.ts b/src/scripts/add-uid.ts new file mode 100644 index 0000000..be00b92 --- /dev/null +++ b/src/scripts/add-uid.ts @@ -0,0 +1,35 @@ +import { AiAgent } from '@/models/agent.ts'; +import { RouterCodeModel } from '@/models/code.ts'; +import { Prompt } from '@/models/prompt.ts'; + +import { User } from '@/models/user.ts'; +import { ContainerModel } from '@/routes/container/models/index.ts'; +import { PageModel } from '@/routes/page/models/index.ts'; +import { ResourceModel } from '@/routes/resource/models/index.ts'; + +// declare uid: string; +// uid: { +// type: DataTypes.UUID, +// allowNull: true, +// }, +// 系统表 +export const stystemTables = [AiAgent, RouterCodeModel, Prompt]; + +export const userTables = [ContainerModel, PageModel, ResourceModel]; + +const rootUid = '14206305-8b5c-44cc-b177-766cfe2e452f'; + +const updateUser = async () => { + const updateTables = [...userTables] as any[]; + for (let Table of updateTables) { + // const res = await ContainerModel.update({ uid: rootUid }, { where: { uid: null } }); + try { + const list = await Table.update({ uid: rootUid }, { where: { uid: null } }); + console.log('update--', list.length); + } catch (e) { + console.log(e); + } + } +}; + +// updateUser();