一直正开发时,又优化了相关的表,现在的表结构为:
c
/*
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 80012 (8.0.12)
Source Host : localhost:3306
Source Schema : chat
Target Server Type : MySQL
Target Server Version : 80012 (8.0.12)
File Encoding : 65001
Date: 03/08/2024 19:27:31
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for blacklists
-- ----------------------------
DROP TABLE IF EXISTS `blacklists`;
CREATE TABLE `blacklists` (
`user_id` int(11) NULL DEFAULT NULL,
`blocked_user_id` int(11) NULL DEFAULT NULL,
`created_at` datetime NULL DEFAULT NULL,
INDEX `user_id`(`user_id` ASC) USING BTREE,
INDEX `blocked_user_id`(`blocked_user_id` ASC) USING BTREE,
CONSTRAINT `blacklists_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `blacklists_ibfk_2` FOREIGN KEY (`blocked_user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for chatgroups
-- ----------------------------
DROP TABLE IF EXISTS `chatgroups`;
CREATE TABLE `chatgroups` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`description` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
`avatar_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`owner_id` int(11) NULL DEFAULT NULL,
`created_at` datetime NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `owner_id`(`owner_id` ASC) USING BTREE,
CONSTRAINT `chatgroups_ibfk_1` FOREIGN KEY (`owner_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for friends
-- ----------------------------
DROP TABLE IF EXISTS `friends`;
CREATE TABLE `friends` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NULL DEFAULT NULL,
`group_friend_id` int(11) NULL DEFAULT NULL,
`type` enum('user','group') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`status` enum('pending','accepted','blocked') CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT 'pending',
`created_at` datetime NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `user_id`(`user_id` ASC) USING BTREE,
CONSTRAINT `friends_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for invites
-- ----------------------------
DROP TABLE IF EXISTS `invites`;
CREATE TABLE `invites` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`inviter_id` int(11) NULL DEFAULT NULL,
`invitee_id` int(11) NULL DEFAULT NULL,
`group_id` int(11) NULL DEFAULT NULL,
`group_avatar` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`inviter_avatar` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`invitee_avatar` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`status` enum('pending','accepted','declined') CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT 'pending',
`created_at` datetime NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `inviter_id`(`inviter_id` ASC) USING BTREE,
INDEX `invitee_id`(`invitee_id` ASC) USING BTREE,
INDEX `group_id`(`group_id` ASC) USING BTREE,
CONSTRAINT `invites_ibfk_1` FOREIGN KEY (`inviter_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `invites_ibfk_2` FOREIGN KEY (`invitee_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `invites_ibfk_3` FOREIGN KEY (`group_id`) REFERENCES `chatgroups` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for messages
-- ----------------------------
DROP TABLE IF EXISTS `messages`;
CREATE TABLE `messages` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`fid` int(11) NULL DEFAULT NULL,
`tid` int(11) NULL DEFAULT NULL,
`receiver_type` enum('user','group') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`type` enum('text','audio','video','image','join','left','broadcast','kick') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`content` text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`avatar` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`is_retracted` tinyint(1) NULL DEFAULT 0,
`retracted_at` datetime NULL DEFAULT NULL,
`created_at` datetime NULL DEFAULT NULL,
`sn` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '唯一码',
`group_name` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',
PRIMARY KEY (`id`) USING BTREE,
INDEX `sender_id`(`fid` ASC) USING BTREE,
CONSTRAINT `messages_ibfk_1` FOREIGN KEY (`fid`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`password` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`email` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`avatar_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`brief` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
`created_at` datetime NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `username`(`username` ASC) USING BTREE,
UNIQUE INDEX `email`(`email` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
用express 开发相关的model:
c
module.exports = (sequelize, DataTypes) => {
const User = require('./User')(sequelize, DataTypes); // 确保 User 模型正确导入
const Blacklist = sequelize.define('Blacklist', {
user_id: {
type: DataTypes.INTEGER,
references: {
model: User,
key: 'id',
},
},
blocked_user_id: {
type: DataTypes.INTEGER,
references: {
model: User,
key: 'id',
},
},
created_at: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
}, {
timestamps: false,
primaryKey: false,
});
// 移除默认的主键 'id'
Blacklist.removeAttribute('id');
return Blacklist;
};
c
module.exports = (sequelize, DataTypes) => {
const User = require('./User')(sequelize, DataTypes); // 确保 User 模型正确导入
const ChatGroup = sequelize.define('ChatGroup', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING(100),
allowNull: false,
},
description: {
type: DataTypes.TEXT,
},
avatar_url: {
type: DataTypes.STRING(255),
},
owner_id: {
type: DataTypes.INTEGER,
references: {
model: User,
key: 'id',
},
},
created_at: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
}, {
timestamps: false,
});
return ChatGroup;
};
c
module.exports = (sequelize, DataTypes) => {
const User = require('./User')(sequelize, DataTypes); // 确保 User 模型正确导入
const Friend = sequelize.define('Friend', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
user_id: {
type: DataTypes.INTEGER,
references: {
model: User,
key: 'id',
},
},
group_friend_id: {
type: DataTypes.INTEGER,
},
type: {
type: DataTypes.ENUM('user', 'group'),
allowNull: false,
},
status: {
type: DataTypes.ENUM('pending', 'accepted', 'blocked'),
defaultValue: 'pending',
},
created_at: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
}, {
timestamps: false,
primaryKey: false,
});
//Friend.removeAttribute('id');
return Friend;
};
c
const Sequelize = require('sequelize');
const sequelize = new Sequelize('chat', 'root', 'asd123', {
host: 'localhost',
dialect: 'mysql', // 或 'postgres', 'sqlite', 'mssql'
});
const User = require('./user')(sequelize, Sequelize.DataTypes);
const Friend = require('./friend')(sequelize, Sequelize.DataTypes);
const ChatGroup = require('./chatGroup')(sequelize, Sequelize.DataTypes);
const Blacklist = require('./blacklist')(sequelize, Sequelize.DataTypes);
const Invite = require('./invite')(sequelize, Sequelize.DataTypes);
const Message = require('./message')(sequelize, Sequelize.DataTypes);
const db = {
sequelize,
Sequelize,
User,
Friend,
ChatGroup,
Blacklist,
Invite,
Message
};
module.exports = db;
c
module.exports = (sequelize, DataTypes) => {
const User = require('./User')(sequelize, DataTypes); // 确保 User 模型正确导入
const ChatGroup = require('./ChatGroup')(sequelize, DataTypes); // 确保 ChatGroup 模型正确导入
const Invite = sequelize.define('Invite', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
inviter_id: {
type: DataTypes.INTEGER,
references: {
model: User,
key: 'id',
},
},
invitee_id: {
type: DataTypes.INTEGER,
references: {
model: User,
key: 'id',
},
},
group_id: {
type: DataTypes.INTEGER,
references: {
model: ChatGroup,
key: 'id',
},
},
group_avatar: {
type: DataTypes.STRING(255),
},
inviter_avatar: {
type: DataTypes.STRING(255),
},
invitee_avatar: {
type: DataTypes.STRING(255),
},
status: {
type: DataTypes.ENUM('pending', 'accepted', 'declined'),
defaultValue: 'pending',
},
created_at: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
}, {
timestamps: false,
});
return Invite;
};
c
module.exports = (sequelize, DataTypes) => {
const User = require('./User')(sequelize, DataTypes); // 确保 User 模型正确导入
const ChatGroup = require('./ChatGroup')(sequelize, DataTypes); // 确保 ChatGroup 模型正确导入
const Message = sequelize.define('Message', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
fid: {
type: DataTypes.INTEGER,
references: {
model: User,
key: 'id',
},
allowNull: true,
},
tid: {
type: DataTypes.INTEGER,
allowNull: true,
},
type: {
type: DataTypes.ENUM('text', 'audio', 'video', 'image','broadcast','left','kick','withdraw','join'),
allowNull: false,
},
content: {
type: DataTypes.TEXT,
allowNull: false,
},
avatar: {
type: DataTypes.STRING(255),
allowNull: true,
},
is_retracted: {
type: DataTypes.BOOLEAN,
defaultValue: false,
},
retracted_at: {
type: DataTypes.DATE,
allowNull: true,
},
created_at: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
group_name:{
type:DataTypes.STRING(10),
allowNull: true,
},
user_name:{
type: DataTypes.STRING(255),
allowNull: true,
},
sn: {
type: DataTypes.STRING(255),
allowNull: true,
},
}, {
timestamps: false,
underscored: true, // 使用下划线风格以符合数据库字段命名
});
return Message;
};
c
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
username: {
type: DataTypes.STRING(50),
allowNull: false,
unique: true,
},
password: {
type: DataTypes.STRING(100),
allowNull: false,
},
email: {
type: DataTypes.STRING(100),
unique: true,
},
avatar_url: {
type: DataTypes.STRING(255),
},
brief: {
type: DataTypes.TEXT,
},
created_at: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
}, {
timestamps: false,
});
return User;
};
聊天代码进行了调整:
c
const socketIo = require('socket.io');
function setupChat(server) {
const io = socketIo(server, {
cors: {
origin: "*",
methods: ["GET", "POST"]
}
});
const groups = {}; // 存储用户与群组的映射
const kickedUsers = {}; // 存储被踢出用户的信息
const groupUsers = {}; // 存储每个群组中的用户列表
io.on('connection', (socket) => {
// console.log('New user connected');
// 用户加入群组
socket.on('joinGroup', ({ groupName, userName }) => {
if (!kickedUsers[groupName] || !kickedUsers[groupName].includes(userName)) {
socket.join(groupName);
// 更新用户列表
if (!groupUsers[groupName]) {
groupUsers[groupName] = [];
}
if (!groupUsers[groupName].includes(userName)) {
groupUsers[groupName].push(userName);
}
groups[socket.id] = { groupName, userName };
console.log( `${userName} has joined the group`)
socket.to(groupName).emit('message',{'type':'join',content:`${userName} 加入`});
// 发送当前用户列表到群组
io.to(groupName).emit('userList', groupUsers[groupName]);
console.log(`${userName} joined group ${groupName}`);
} else {
socket.emit('message', `您已被踢出群组 ${groupName}, 无法重新加入。`);
}
});
// 发送消息
socket.on('sendMessage', ({sn, group_name,avatar, content, user_name,type,fid,tid ,created_at}) => {
if (!kickedUsers[group_name] || !kickedUsers[group_name].includes(user_name)) {
io.to(group_name).emit('message', {sn, group_name,avatar, content, user_name,type,fid,tid ,created_at});
io.emit('message', {sn, group_name,avatar, content, user_name,'type':'broadcast',fid,tid ,created_at});
console.log({sn, group_name,avatar, content, user_name,type,fid,tid ,created_at});
} else {
socket.emit('message', `您已被踢出群组 ${group_name}, 无法发送消息。`);
}
});
// 踢人
socket.on('kickUser', ({ groupName, userName }) => {
for (let id in groups) {
if (groups[id].userName === userName && groups[id].groupName === groupName) {
io.sockets.sockets.get(id).leave(groupName);
io.to(groupName).emit('message', `${userName} 已被踢出群组`);
// 从用户列表中删除
if (groupUsers[groupName]) {
groupUsers[groupName] = groupUsers[groupName].filter(user => user !== userName);
io.to(groupName).emit('userList', groupUsers[groupName]);
}
console.log(`${userName} 被踢出群组 ${groupName}`);
if (!kickedUsers[groupName]) {
kickedUsers[groupName] = [];
}
kickedUsers[groupName].push(userName);
break;
}
}
});
// 用户断开连接
socket.on('disconnect', () => {
if (groups[socket.id]) {
const { groupName, userName } = groups[socket.id];
// 从用户列表中删除
if (groupUsers[groupName]) {
groupUsers[groupName] = groupUsers[groupName].filter(user => user !== userName);
io.to(groupName).emit('userList', groupUsers[groupName]);
}
socket.to(groupName).emit('message', {'type':'left',content:`${userName} 离开`});
delete groups[socket.id];
console.log(`${userName} 已离开群组 ${groupName}`);
}
});
});
return io;
}
module.exports = setupChat;
启动页为:
c
const express = require('express');
const http = require('http');
const cors = require('cors');
const bodyParser = require('body-parser');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const db = require('./src/models');
const { User, Friend, ChatGroup, Blacklist, Invite, Message, sequelize } = require('./src/models');
const multer = require('multer');
const path = require('path');
const fs = require('fs');
const { Op } = require('sequelize');
const setupChat = require('./src/chat');
const app = express();
const server = http.createServer(app);
// 设置聊天
const io = setupChat(server);
// 使用中间件
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
const port = 3000;
const SECRET_KEY = 'mykeyssssssd%#@##$#@$#$@$#@$$'; // 更改为实际的密钥
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (token == null) return res.json({code:-1,message:'expire'});
jwt.verify(token, SECRET_KEY, (err, user) => {
if (err) return res.json({code:-1,message:'expire'});
req.user = user;
next();
});
};
// 设置文件存储配置
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/');
},
filename: (req, file, cb) => {
cb(null, `${Date.now()}-${file.originalname}`);
}
});
const upload = multer({ storage: storage });
// 创建 uploads 目录
const uploadsDir = path.join(__dirname, 'uploads');
if (!fs.existsSync(uploadsDir)) {
fs.mkdirSync(uploadsDir);
}
// 文件上传接口
app.post('/upload', upload.single('avatar'), (req, res) => {
if (!req.file) {
return res.status(400).json({ error: 'No file uploaded' });
}
const fileUrl = `http://localhost:3000/uploads/${req.file.filename}`;
res.json({code:0,message:'图片上传成功', data: fileUrl });
});
// 提供静态文件服务
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));
app.post('/register', async (req, res) => {
try {
const { username, password } = req.body;
console.log('Received registration request for:', username);
if (username.length < 6 || username.length > 10 || password.length < 6 || password.length > 10) {
console.log('Invalid username or password length');
return res.status(400).json({ error: 'Username and password must be 6-10 characters long' });
}
const hashedPassword = await bcrypt.hash(password, 10);
console.log('Password hashed successfully');
console.log('Attempting to create user in database');
const user = await User.create({ username, password: hashedPassword });
console.log('User created:', user.toJSON());
res.status(201).json({ message: 'User registered successfully' });
} catch (error) {
console.error('Error in registration:', error);
if (error.name === 'SequelizeUniqueConstraintError') {
return res.status(400).json({ error: 'Username already exists' });
}
res.status(500).json({ error: error.message || 'An error occurred during registration' });
}
});
// 用户登录
app.post('/login', async (req, res) => {
try {
const { username, password } = req.body;
console.log({ username, password });
if (username.length < 6 || username.length > 10 || password.length < 6 || password.length > 10) {
return res.status(400).json({ code: 0, msg: '用户名和密码必须是6-10个字符长', data: null });
}
const user = await User.findOne({ where: { username } });
console.log(user);
if (!user || !await bcrypt.compare(password, user.password)) {
return res.status(401).json({ code: 0, msg: '无效凭证', data: null });
}
const token = jwt.sign({ id: user.id }, SECRET_KEY, { expiresIn: '1h' });
res.json({ code: 1, msg: '登录成功', data: { token } });
} catch (error) {
console.log(error);
res.status(500).json({ code: 0, msg: '登录时出错', data: null });
}
});
// 添加好友
app.post('/addFriend', authenticateToken, async (req, res) => {
const { friendId } = req.body;
const userId = req.user.id;
try {
const friend = await User.findByPk(friendId);
if (!friend){
return res.status(404).json({ error:'未找到朋友' });
}
await Friend.create({ user_id: userId, friend_id: friendId });
res.json({ message:'成功添加好友' });
}catch (error){
res.status(500).json({ error:'添加好友时出错' });
}
});
// 获取好友列表
app.get('/friends', authenticateToken, async (req, res) => {
try {
const userId = req.user.id;
const { page = 1, perPage = 20 } = req.query;
// 计算分页参数
const offset = (page - 1) * perPage;
const limit = parseInt(perPage);
const friends = await Friend.findAndCountAll({
where: {
[Op.or]: [
{
type: 'user',
[Op.or]: [
{ user_id: userId },
{ group_friend_id: userId }
]
},
{
type: 'group',
user_id: userId
}
]
},
offset,
limit
});
// 判断是否还有更多数据
const hasMoreFriends = friends.count > offset + limit;
const friendDataPromises = friends.rows.map(async (item) => {
if (item.type == 'user') {
const user = await User.findOne({
where: { id: item.group_friend_id },
attributes: ['id', 'username', 'email', 'avatar_url', 'brief']
});
return { ...item.get(), user };
}
if (item.type == 'group') {
const group = await ChatGroup.findOne({
where: { id: item.group_friend_id },
attributes: ['id', 'name', 'description', 'avatar_url']
});
return { ...item.get(), group };
}
});
const friendsData = await Promise.all(friendDataPromises);
return res.json({
code: 0,
message: '返回成功',
data: friendsData,
hasMoreFriends
});
} catch (error) {
return res.json({ code: -1, message: error });
}
});
app.get('/checkFriend', authenticateToken, async (req, res) => {
try {
const userId = req.user.id;
let { Id } = req.query;
if( /^g_\d+$/.test(Id)){
//是group
Id = Id.replace("g_", "");
const isFriend = await Friend.findOne({
where: { user_id: userId, group_friend_id:Id},
attributes: ['id', 'user_id', 'group_friend_id','type']
});
if(isFriend){
return res.json({ code: 0, message: 'User is a friend', data: isFriend });
}else{
return res.json({ code: 1, message: 'User is not a friend' });
}
}
const isFriend = await Friend.findOne({
where: { id: Id,type:'user' },
attributes: ['id', 'user_id', 'group_friend_id','type']
});
if (isFriend){
if(isFriend.user_id==userId ||isFriend.group_friend_id==userId){
return res.json({ code: 0, message: 'User is a friend', data: isFriend });
}
return res.json({ code: 1, message: 'User is not a friend' });
}else{
return res.json({ code: 1, message: 'User is not a friend' });
}
} catch (error) {
return res.json({ code: -1, message: error.message });
}
});
app.post('/addmessage', authenticateToken, async (req, res) => {
const { sn, group_name, avatar, content, type, user_name, fid, tid } = req.body;
try {
// 插入新消息
const newMessage = await Message.create({
sn,
group_name,
avatar,
content,
type,
user_name,
fid,
tid,
is_retracted:0,
});
res.json({ code: 0, message: '消息添加成功', data: newMessage });
} catch (error) {
console.error('添加消息失败:', error);
res.json({ code: -1, message: '消息添加失败' });
}
});
// 获取用户信息接口
app.get('/user', authenticateToken, async (req, res) => {
try {
// 确保 `req.user` 和 `req.user.id` 存在
if (!req.user || !req.user.id) {
return res.status(400).json({ error: '用户 ID 未找到' });
}
const user = await User.findByPk(req.user.id, {
attributes: ['id', 'username', 'email', 'avatar_url', 'brief', 'created_at']
});
if (!user) {
//console.warn("User not found with ID:", req.user.id);
return res.status(404).json({ error: '用户未找到' });
}
res.json(user);
} catch (error) {
res.status(500).json({ error: '获取用户信息时出错' });
}
});
app.post('/user/updateAvatar', authenticateToken, async (req, res) => {
const { avatar_url } = req.body;
try {
await User.update({ avatar_url }, { where: { id: req.user.id } });
res.json({code:0, message:'头像更新成功',data:avatar_url });
} catch (error) {
res.json({code:-1, message:'头象更新失败A'});
}
});
app.post('/user/updateBrief', authenticateToken, async (req, res) => {
const { brief } = req.body;
const userId = req.user.id; // Assuming the user ID is stored in the token
if (!brief) {
return res.status(400).json({ code: 1, message: 'Brief is required' });
}
try {
// Update the user's brief in the database
const [affectedRows] = await User.update(
{ brief }, // Fields to update
{ where: { id: userId } } // Condition to find the user
);
if (affectedRows === 0) {
return res.status(404).json({ code: 1, message: 'User not found' });
}
res.status(200).json({ code: 0, message: 'Brief updated successfully' });
} catch (error) {
//console.error('Error updating brief:', error);
res.status(500).json({ code: 1, message: 'Internal server error' });
}
});
// 创建群组接口
app.post('/groups', authenticateToken, upload.single('avatar'), async (req, res) => {
try {
//console.log('req.body:', req.body); // 调试输出请求体
const { name, description ,avatar_url} = req.body;
const owner_id = req.user.id;
if (name.length < 3 || name.length > 10) {
return res.status(400).json({ error: '群名必须在3到10个汉字之间' });
}
if (description.length < 5 || description.length > 50) {
return res.status(400).json({ error: '群说明必须在5到50个汉字之间' });
}
const existingGroup = await ChatGroup.findOne({ where: { name } });
if (existingGroup) {
return res.json({code:-1, message: '群名已存在' });
}
const group = await ChatGroup.create({ name, description, avatar_url, owner_id });
await Friend.create({ user_id: owner_id, group_friend_id: group.id, type: 'group', status: 'accepted' });
return res.json({ code: 0, message: '群组创建成功', group });
} catch (error) {
return res.json({code:-1, message: '创建群组时出错' });
}
});
// 获取群组信息接口
app.get('/groups/:id', authenticateToken, async (req, res) => {
try {
const group = await ChatGroup.findByPk(req.params.id);
if (!group){
return res.status(404).json({ error:'群组未找到' });
}
res.json(group);
}catch (error){
res.status(500).json({ error:'获取群组信息时出错' });
}
});
app.get('/groups', authenticateToken, async (req, res) => {
try {
const userId = req.user.id;
//console.log('userId',userId)
const groups = await ChatGroup.findAll({ where: { owner_id: userId } });
//console.log('groups',groups)
return res.json({ code: 0, data: groups });
} catch (error) {
//console.error('Error fetching groups:', error);
return res.json({ code: -1, message: 'Failed to fetch groups' });
}
});
app.post('/group/update', authenticateToken, async (req, res) => {
try {
const { id, name, description, avatar_url } = req.body;
// Check if the group name already exists and is not the current group being updated
const existingGroup = await ChatGroup.findOne({
where: {
name,
id: { [Op.ne]: id } // Use Op from Sequelize
}
});
//
// console.log('Op:', Op); // Should not be undefined
// console.log('Query:', {
// name,
// id: { [Op.ne]: id }
// });
if (existingGroup) {
return res.json({ code: -2, message: '群名重复' });
}
await ChatGroup.update({ name, description, avatar_url }, { where: { id } });
return res.json({ code: 0, message: '群名创建成功' });
} catch (error) {
// console.error('Error updating group:', error);
return res.json({ code: -1, message: '创建失败' });
}
});
app.post('/user/updateEmail', authenticateToken, async (req, res) => {
try {
const userId = req.user.id;
const { email } = req.body;
await User.update({ email }, { where: { id: userId } });
return res.json({ code: 0, message: 'Email updated successfully' });
} catch (error) {
// console.error('Error updating email:', error);
return res.json({ code: -1, message: 'Failed to update email' });
}
});
app.get('/user', authenticateToken, async (req, res) => {
try {
const user = await User.findByPk(req.user.id, {
attributes: ['id', 'username', 'email', 'avatar']
});
if (!user) {
return res.status(404).json({ error: '用户未找到' });
}
res.json(user);
} catch (error) {
res.status(500).json({ error: '获取用户信息时出错' });
}
});
app.post('/logout', authenticateToken, (req, res) => {
// 这里可以添加一些服务器端的登出逻辑
// 比如清除服务器端的 session 或标记 token 为无效
res.json({ message: '成功登出' });
});
const PORT = process.env.PORT || port;
server.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});