FastGPT如何增减用户

背景

开源版本的FastGPT默认只有一个超级用户root,为了更好地管理应用和知识库,可以通过操作MongoDB数据库来增加新的用户和团队。

所需环境
  • 已安装并运行的FastGPT实例
  • MongoDB客户端工具(如Mongo Shell或Robo 3T等)
操作步骤
  1. 启动MongoDB客户端
    在命令行中启动MongoDB客户端,并连接到FastGPT使用的数据库。

  2. 增加新用户
    users集合中插入一条新记录,这条记录包含新用户的详细信息,包括用户名、密码等字段。

    db.getCollection("users").insert({
        username: "demo",
        password: "756bc47cb5215dc3329ca7e1f7be33a2dad68990bb94b76d90aa07f4e44a233a", // 请使用安全的方式加密密码
        status: "active",
        avatar: "/icon/human.svg",
        balance: NumberInt("100000"),
        promotionRate: NumberInt("10"),
        timezone: "Asia/Shanghai",
        createTime: new ISODate()
    });
    
  3. 创建新团队
    teams集合中插入一条新记录,这条记录包含团队的基本信息。

    db.getCollection("teams").insert({
        name: "New Team",
        ownerId: ObjectId("65916f1a52ac39c5d10bb505"), // 新创建用户的ObjectId
        avatar: "/icon/newteam.svg",
        createTime: new ISODate(),
        balance: NumberInt("100000"),
        maxSize: NumberInt("10"),
        __v: NumberInt("0")
    });
    
  4. 将用户加入团队
    team_members集合中插入一条新记录,这条记录关联了用户和团队。

    db.getCollection("team_members").insert({
        teamId: ObjectId("65916f3952ac39c5d10bb506"), // 团队的ObjectId
        userId: ObjectId("65916f1a52ac39c5d10bb505"), // 用户的ObjectId
        name: "Owner",
        role: "owner",
        status: "active",
        createTime: new ISODate(),
        defaultTeam: true
    });
    
更方便的方式

有了这么多AI,当然可以直接增加管理页面
在这里插入图片描述

  • user.tsx
import React, { useState, useEffect } from 'react';
import {
    Box,
    Button,
    FormControl,
    FormLabel,
    Input,
    VStack,
    HStack,
    Table,
    Thead,
    Tbody,
    Tr,
    Th,
    Td,
    Modal,
    ModalOverlay,
    ModalContent,
    ModalHeader,
    ModalBody,
    ModalCloseButton,
    useDisclosure,
    useToast,
    Select,
} from '@chakra-ui/react';
import { serviceSideProps } from '@/web/common/utils/i18n';
const fetchUsers = async () => {
    const response = await fetch('/api/admin/users');
    if (!response.ok) throw new Error('Failed to fetch users');
    return response.json();
};

const addUser = async (userData) => {
    const response = await fetch('/api/admin/users', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(userData),
    });
    if (!response.ok) throw new Error('Failed to add user');
    return response.json();
};

const updateUser = async (userId, userData) => {
    const response = await fetch(`/api/admin/users/${userId}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(userData),
    });
    if (!response.ok) throw new Error('Failed to update user');
    return response.json();
};

const deleteUser = async (userId) => {
    const response = await fetch(`/api/admin/users/${userId}`, { method: 'DELETE' });
    if (!response.ok) throw new Error('Failed to delete user');
    return response.json();
};

export default function UserManagement() {
    const [users, setUsers] = useState([]);
    const [currentUser, setCurrentUser] = useState(null);
    const { isOpen, onOpen, onClose } = useDisclosure();
    const toast = useToast();

    useEffect(() => {
        loadUsers();
    }, []);

    const loadUsers = async () => {
        try {
            const fetchedUsers = await fetchUsers();
            setUsers(fetchedUsers);
        } catch (error) {
            toast({
                title: "Failed to load users.",
                description: error.message,
                status: "error",
                duration: 3000,
                isClosable: true,
            });
        }
    };

    const handleAddUser = async (userData) => {
        try {
            const newUser = await addUser(userData);
            setUsers([...users, newUser.user]);
            onClose();
            toast({
                title: "User added.",
                status: "success",
                duration: 2000,
                isClosable: true,
            });
        } catch (error) {
            toast({
                title: "Failed to add user.",
                description: error.message,
                status: "error",
                duration: 3000,
                isClosable: true,
            });
        }
    };

    const handleUpdateUser = async (userData) => {
        try {
            const updatedUser = await updateUser(currentUser._id, userData);
            setUsers(users.map(user => user._id === updatedUser._id ? updatedUser : user));
            onClose();
            toast({
                title: "User updated.",
                status: "success",
                duration: 2000,
                isClosable: true,
            });
        } catch (error) {
            toast({
                title: "Failed to update user.",
                description: error.message,
                status: "error",
                duration: 3000,
                isClosable: true,
            });
        }
    };

    const handleDeleteUser = async (userId) => {
        try {
            await deleteUser(userId);
            setUsers(users.filter(user => user._id !== userId));
            toast({
                title: "User deleted.",
                status: "success",
                duration: 2000,
                isClosable: true,
            });
        } catch (error) {
            toast({
                title: "Failed to delete user.",
                description: error.message,
                status: "error",
                duration: 3000,
                isClosable: true,
            });
        }
    };

    const openAddModal = () => {
        setCurrentUser(null);
        onOpen();
    };

    const openEditModal = (user) => {
        setCurrentUser(user);
        onOpen();
    };

    return (
        <Box p={5}>
            <Button onClick={openAddModal} colorScheme="blue" mb={4}>
                Add User
            </Button>
            <Table variant="simple">
                <Thead>
                    <Tr>
                        <Th>Username</Th>
                        <Th>Status</Th>
                        <Th>Balance</Th>
                        <Th>Promotion Rate</Th>
                        <Th>Timezone</Th>
                        <Th>Actions</Th>
                    </Tr>
                </Thead>
                <Tbody>
                    {users.map((user) => (
                        <Tr key={user._id}>
                            <Td>{user.username}</Td>
                            <Td>{user.status}</Td>
                            <Td>{user.balance}</Td>
                            <Td>{user.promotionRate}%</Td>
                            <Td>{user.timezone}</Td>
                            <Td>
                                <HStack spacing={2}>
                                    <Button size="sm" onClick={() => openEditModal(user)}>
                                        Edit
                                    </Button>
                                    <Button size="sm" colorScheme="red" onClick={() => handleDeleteUser(user._id)}>
                                        Delete
                                    </Button>
                                </HStack>
                            </Td>
                        </Tr>
                    ))}
                </Tbody>
            </Table>

            <Modal isOpen={isOpen} onClose={onClose}>
                <ModalOverlay />
                <ModalContent>
                    <ModalHeader>{currentUser ? 'Edit User' : 'Add User'}</ModalHeader>
                    <ModalCloseButton />
                    <ModalBody>
                        <UserForm user={currentUser} onSubmit={currentUser ? handleUpdateUser : handleAddUser} />
                    </ModalBody>
                </ModalContent>
            </Modal>
        </Box>
    );
}

function UserForm({ user, onSubmit }) {
    const [formData, setFormData] = useState(user || {
        username: '',
        password: '',
        status: 'active',
        balance: 100000,
        promotionRate: 10,
        timezone: 'Asia/Shanghai'
    });

    const handleChange = (e) => {
        const { name, value } = e.target;
        setFormData({ ...formData, [name]: value });
    };

    const handleSubmit = (e) => {
        e.preventDefault();
        onSubmit(formData);
    };

    return (
        <form onSubmit={handleSubmit}>
            <VStack spacing={4}>
                <FormControl isRequired>
                    <FormLabel>Username</FormLabel>
                    <Input name="username" value={formData.username} onChange={handleChange} />
                </FormControl>
                {!user && (
                    <FormControl isRequired>
                        <FormLabel>Password</FormLabel>
                        <Input name="password" type="password" value={formData.password} onChange={handleChange} />
                    </FormControl>
                )}
                <FormControl>
                    <FormLabel>Status</FormLabel>
                    <Select name="status" value={formData.status} onChange={handleChange}>
                        <option value="active">Active</option>
                        <option value="inactive">Inactive</option>
                    </Select>
                </FormControl>
                <FormControl>
                    <FormLabel>Balance</FormLabel>
                    <Input name="balance" type="number" value={formData.balance} onChange={handleChange} />
                </FormControl>
                <FormControl>
                    <FormLabel>Promotion Rate (%)</FormLabel>
                    <Input name="promotionRate" type="number" value={formData.promotionRate} onChange={handleChange} />
                </FormControl>
                <FormControl>
                    <FormLabel>Timezone</FormLabel>
                    <Input name="timezone" value={formData.timezone} onChange={handleChange} />
                </FormControl>
                <Button type="submit" colorScheme="blue">
                    {user ? 'Update' : 'Add'} User
                </Button>
            </VStack>
        </form>
    );
}

export async function getServerSideProps(content: any) {
    return {
        props: {
            ...(await serviceSideProps(content, ['publish', 'user']))
        }
    };
}

  • [id].js
import { connectToDatabase } from '@/service/mongo';
import { hashStr } from '@fastgpt/global/common/string/tools';
import { MongoUser } from '@fastgpt/service/support/user/schema';
import { MongoTeam } from '@fastgpt/service/support/user/team/teamSchema';
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';

export default async function handler(req, res) {
  const {
    query: { id },
    method,
  } = req;

  await connectToDatabase();

  switch (method) {
    case 'GET':
      try {
        const user = await MongoUser.findById(id).select('-password');
        if (!user) {
          return res.status(404).json({ error: 'User not found' });
        }
        res.status(200).json(user);
      } catch (error) {
        res.status(500).json({ error: 'Error fetching user' });
      }
      break;

    case 'PUT':
      try {
        const { username, status, avatar, balance, promotionRate, timezone, password } = req.body;
        const updateDoc = {
          username,
          status,
          avatar,
          balance,
          promotionRate,
          timezone,
        };

        if (password) {
          updateDoc.password = hashStr(password);
        }

        const user = await MongoUser.findByIdAndUpdate(id, updateDoc, {
          new: true,
          runValidators: true,
        }).select('-password');

        if (!user) {
          return res.status(404).json({ error: 'User not found' });
        }

        res.status(200).json(user);
      } catch (error) {
        res.status(500).json({ error: 'Error updating user' });
      }
      break;

    case 'DELETE':
      try {
        const deletedUser = await MongoUser.findByIdAndDelete(id);
        if (!deletedUser) {
          return res.status(404).json({ error: 'User not found' });
        }

        // Remove user from teams
        await MongoTeamMember.deleteMany({ userId: id });

        // Delete teams owned by this user
        const ownedTeams = await MongoTeam.find({ ownerId: id });
        for (const team of ownedTeams) {
          await MongoTeamMember.deleteMany({ teamId: team._id });
          await MongoTeam.findByIdAndDelete(team._id);
        }

        res.status(200).json({ success: true });
      } catch (error) {
        res.status(500).json({ error: 'Error deleting user' });
      }
      break;

    default:
      res.setHeader('Allow', ['GET', 'PUT', 'DELETE']);
      res.status(405).end(`Method ${method} Not Allowed`);
  }
}
  • index.js
// pages/api/users/index.js
import { connectToDatabase } from '@/service/mongo';
import { MongoUser } from '@fastgpt/service/support/user/schema';
import { MongoTeam } from '@fastgpt/service/support/user/team/teamSchema';
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
import { hashStr } from '@fastgpt/global/common/string/tools';
import { authCert } from '@fastgpt/service/support/permission/auth/common';

export default async function handler(req, res) {
  const { method } = req;
  await connectToDatabase();

  const { userId } = await authCert({ req, authToken: true });

  const curUser = await MongoUser.findById(userId).select('-password');
  if (curUser.username !== 'root') {
    return res.status(200).json([]);
  }

  switch (method) {
    case 'GET':
      try {
        console.log('GET /api/users', MongoUser);
        const users = await MongoUser.find({ username: { $ne: 'root' } }).select('-password');
        res.status(200).json(users);
      } catch (error) {
        console.log(error);
        res.status(500).json({ error: 'Error fetching users' });
      }
      break;

    case 'POST':
      try {
        const { username, password, status, avatar, balance, promotionRate, timezone } = req.body;

        // Check if user already exists
        const existingUser = await MongoUser.findOne({ username });
        if (existingUser) {
          return res.status(400).json({ error: 'Username already exists' });
        }
        console.log('POST /api/users', password, hashStr(password), hashStr(hashStr(password)));
        // Hash password
        const hashedPassword = hashStr(password);

        const newUser = new MongoUser({
          username,
          password: hashedPassword,
          status,
          avatar,
          balance,
          promotionRate,
          timezone,
        });

        const savedUser = await newUser.save();

        // Create a new team for the user
        const team = new MongoTeam({
          name: `${username}'s Team`,
          ownerId: savedUser._id,
        });
        const savedTeam = await team.save();

        // Add user to team_members
        const teamMember = new MongoTeamMember({
          teamId: savedTeam._id,
          userId: savedUser._id,
          name: 'Owner',
          role: 'owner',
          defaultTeam: true,
        });
        await teamMember.save();

        res.status(201).json({ success: true, user: savedUser.toObject({ versionKey: false, transform: (doc, ret) => { delete ret.password; return ret; } }) });
      } catch (error) {
        console.log(error);
        res.status(500).json({ error: 'Error creating user' });
      }
      break;

    default:
      res.setHeader('Allow', ['GET', 'POST']);
      res.status(405).end(`Method ${method} Not Allowed`);
  }
}

// pages/api/users/[id].js

  • 访问/admin/user
    在这里插入图片描述
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

problc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值