feat: user org and fix bugs

This commit is contained in:
2024-10-08 03:30:01 +08:00
parent 3c7ef0d6e4
commit 54e3ccb3ff
10 changed files with 422 additions and 113 deletions

View File

@@ -4,7 +4,7 @@ import { app, redis } from '@/app.ts';
import _ from 'lodash';
import { prefixFix } from './util.ts';
import { deleteFiles } from '../file/index.ts';
import { setExpire } from './revoke.ts';
app
.route({
path: 'app',
@@ -23,6 +23,7 @@ app
uid: tokenUser.id,
key: data.key,
},
logging: false,
});
ctx.body = list.map((item) => prefixFix(item, tokenUser.username));
return ctx;
@@ -189,15 +190,7 @@ app
throw new CustomError('app not found');
}
await am.update({ data: { ...am.data, files }, version: app.version });
//
const keys = await redis.keys('user:app:exist:*');
console.log('keys', keys);
const expireKey = 'user:app:exist:' + `${app.key}:${am.user}`;
console.log('expireKey', expireKey);
await redis.set(expireKey, 'v', 'EX', 2);
await new Promise((resolve) => setTimeout(resolve, 2100));
const keys2 = await redis.keys('user:app:exist:*');
console.log('keys2', keys2);
setExpire(app.key, am.user);
ctx.body = 'success';
})
.addTo(app);

View File

@@ -0,0 +1,6 @@
import { redis } from '@/app.ts';
export const setExpire = async (key: string, user: string) => {
const expireKey = 'user:app:exist:' + `${key}:${user}`;
await redis.set(expireKey, 'v', 'EX', 2);
};

View File

@@ -1,6 +1,7 @@
import { CustomError } from '@abearxiong/router';
import { AppModel, AppListModel } from './module/index.ts';
import { app } from '@/app.ts';
import { setExpire } from './revoke.ts';
app
.route({
@@ -68,6 +69,9 @@ app
const newData = { ...app.data, ...data };
const newApp = await app.update({ data: newData, ...rest });
ctx.body = newApp;
if (app.status !== 'running') {
setExpire(newApp.key, app.user);
}
} else {
throw new CustomError('app not found');
}

View File

@@ -1 +1,4 @@
import './list.ts'
import './list.ts';
import './org.ts';
import './me.ts';

View File

@@ -3,7 +3,11 @@ import { User } from '@/models/user.ts';
import { CustomError } from '@abearxiong/router';
app
.route('user', 'list')
.route({
path: 'user',
key: 'list',
middleware: ['auth'],
})
.define(async (ctx) => {
const users = await User.findAll({
attributes: ['id', 'username', 'description', 'needChangePassword'],
@@ -14,106 +18,62 @@ app
})
.addTo(app);
app
.route('user', 'login')
.route({
path: 'user',
key: 'update',
middleware: ['auth'],
})
.define(async (ctx) => {
const { username, password } = ctx.query;
const user = await User.findOne({ where: { username } });
const tokenUser = ctx.state.tokenUser;
const { id, username, password, description } = ctx.query.data || {};
const user = await User.findByPk(id);
if (user.id !== tokenUser.id) {
throw new CustomError(401, 'Permission denied');
}
if (!user) {
new CustomError(401, 'User not found');
throw new CustomError(500, 'user not found');
}
if (user.password !== password) {
new CustomError(401, 'Password error');
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({
path: 'user',
key: 'add',
middleware: ['auth'],
})
.define(async (ctx) => {
const tokenUser = ctx.state.tokenUser;
const { username, password, description } = ctx.query.data || {};
if (!username) {
throw new CustomError(400, 'username is required');
}
const user = await User.createUser(username, password, description);
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 || {};
} 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,
token,
};
})
.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,
};
});
});

124
src/routes/user/me.ts Normal file
View File

@@ -0,0 +1,124 @@
import { app } from '@/app.ts';
import { Org } from '@/models/org.ts';
import { User } from '@/models/user.ts';
import { CustomError } from '@abearxiong/router';
app
.route({
path: 'user',
key: 'me',
middleware: ['auth'],
})
.define(async (ctx) => {
const state = ctx.state?.tokenUser || {};
const { id } = state;
const user = await User.findByPk(id);
if (!user) {
throw new CustomError(500, 'user not found');
}
ctx.body = await user.getInfo();
})
.addTo(app);
app
.route({
path: 'user',
key: 'login',
})
.define(async (ctx) => {
const { username, email, password } = ctx.query;
if (!username && !email) {
throw new CustomError(400, 'username or email is required');
}
let user: User | null = null;
if (username) {
user = await User.findOne({ where: { username } });
}
if (!user && email) {
user = await User.findOne({ where: { email } });
}
if (!user) {
throw new CustomError(500, 'Login Failed');
}
if (!user.checkPassword(password)) {
throw new CustomError(500, '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 || {};
} catch (e) {
throw 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 = await user.getInfo();
})
.addTo(app);
app
.route({
path: 'user',
key: 'switchOrg',
middleware: ['auth'],
})
.define(async (ctx) => {
const tokenUser = ctx.state.tokenUser;
const { username, type = 'org' } = ctx.query.data || {};
if (!username && type === 'org') {
throw new CustomError('username is required');
}
let me: User;
if (tokenUser.uid) {
me = await User.findByPk(tokenUser.uid);
} else {
me = await User.findByPk(tokenUser.id);
}
if (type === 'user') {
const token = await me.createToken();
ctx.body = token;
return;
}
const orgUser = await User.findOne({ where: { username } });
if (!orgUser) {
throw new CustomError('org not found');
}
const user = await Org.findOne({ where: { username } });
const users = user.users;
const index = users.findIndex((u) => u.uid === me.id);
if (index === -1) {
throw new CustomError('Permission denied');
}
const token = await orgUser.createToken(me.id);
ctx.body = token;
})
.addTo(app);

98
src/routes/user/org.ts Normal file
View File

@@ -0,0 +1,98 @@
import { app, sequelize } from '@/app.ts';
import { Org } from '@/models/org.ts';
import { User } from '@/models/user.ts';
import { CustomError } from '@abearxiong/router';
import { Op } from 'sequelize';
app
.route({
path: 'org',
key: 'list',
middleware: ['auth'],
})
.define(async (ctx) => {
const tokenUser = ctx.state.tokenUser;
const list = await Org.findAll({
order: [['updatedAt', 'DESC']],
where: {
users: {
[Op.contains]: [
{
uid: tokenUser.id,
},
],
},
},
});
ctx.body = list;
return ctx;
})
.addTo(app);
app
.route({
path: 'org',
key: 'get',
})
.define(async (ctx) => {
const id = ctx.query.id;
if (!id) {
throw new CustomError('id is required');
}
ctx.body = await Org.findByPk(id);
return ctx;
})
.addTo(app);
app
.route({
path: 'org',
key: 'update',
middleware: ['auth'],
})
.define(async (ctx) => {
const tokenUser = ctx.state.tokenUser;
const { username, description } = ctx.query.data;
if (!username) {
throw new CustomError('username is required');
}
const user = await User.createOrg(username, tokenUser.id, description);
ctx.body = {
id: user.id,
username: user.username,
description: user.description,
};
})
.addTo(app);
app
.route({
path: 'org',
key: 'delete',
middleware: ['auth'],
})
.define(async (ctx) => {
const tokenUser = ctx.state.tokenUser;
const id = ctx.query.id;
if (!id) {
throw new CustomError('id is required');
}
const org = await Org.findByPk(id);
if (!org) {
throw new CustomError('org not found');
}
const username = org.username;
const users = org.users;
const owner = users.find((u) => u.role === 'owner');
if (owner.uid !== tokenUser.id) {
throw new CustomError('Permission denied');
}
await org.destroy({ force: true });
const orgUser = await User.findOne({
where: { username },
});
await orgUser.destroy({ force: true });
ctx.body = 'success';
})
.addTo(app);