优化
This commit is contained in:
89
server/services/core/user/dmlist.service.ts
Normal file
89
server/services/core/user/dmlist.service.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import type { Ref } from '@typegoose/typegoose';
|
||||
import type { Converse } from '../../../models/chat/converse';
|
||||
import type {
|
||||
UserDMList,
|
||||
UserDMListDocument,
|
||||
UserDMListModel,
|
||||
} from '../../../models/user/dmlist';
|
||||
import { TcService, TcContext, TcDbService, db } from 'tailchat-server-sdk';
|
||||
|
||||
interface UserDMListService
|
||||
extends TcService,
|
||||
TcDbService<UserDMListDocument, UserDMListModel> {}
|
||||
class UserDMListService extends TcService {
|
||||
get serviceName(): string {
|
||||
return 'user.dmlist';
|
||||
}
|
||||
|
||||
onInit(): void {
|
||||
this.registerLocalDb(require('../../../models/user/dmlist').default);
|
||||
this.registerAction('addConverse', this.addConverse, {
|
||||
params: {
|
||||
converseId: 'string',
|
||||
},
|
||||
});
|
||||
this.registerAction('removeConverse', this.removeConverse, {
|
||||
params: {
|
||||
converseId: 'string',
|
||||
},
|
||||
});
|
||||
this.registerAction('getAllConverse', this.getAllConverse);
|
||||
}
|
||||
|
||||
async addConverse(ctx: TcContext<{ converseId: string }>) {
|
||||
const userId = ctx.meta.userId;
|
||||
const converseId = ctx.params.converseId;
|
||||
|
||||
const record = await this.adapter.model.findOrCreate({
|
||||
userId,
|
||||
});
|
||||
|
||||
const res = await this.adapter.model.findByIdAndUpdate(record.doc._id, {
|
||||
$addToSet: {
|
||||
converseIds: new db.Types.ObjectId(converseId),
|
||||
},
|
||||
});
|
||||
|
||||
return await this.transformDocuments(ctx, {}, res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除会话
|
||||
*/
|
||||
async removeConverse(ctx: TcContext<{ converseId: string }>) {
|
||||
const userId = ctx.meta.userId;
|
||||
const converseId = ctx.params.converseId;
|
||||
|
||||
const { modifiedCount } = await this.adapter.model
|
||||
.updateOne(
|
||||
{
|
||||
userId,
|
||||
},
|
||||
{
|
||||
$pull: {
|
||||
converseIds: converseId,
|
||||
},
|
||||
}
|
||||
)
|
||||
.exec();
|
||||
|
||||
return { modifiedCount };
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有会话
|
||||
*/
|
||||
async getAllConverse(ctx: TcContext): Promise<Ref<Converse>[]> {
|
||||
const userId = ctx.meta.userId;
|
||||
|
||||
const doc = await this.adapter.model.findOne({
|
||||
userId,
|
||||
});
|
||||
|
||||
const res: UserDMList | null = await this.transformDocuments(ctx, {}, doc);
|
||||
|
||||
return res?.converseIds ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
export default UserDMListService;
|
||||
136
server/services/core/user/friend.service.ts
Normal file
136
server/services/core/user/friend.service.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import type {
|
||||
Friend,
|
||||
FriendDocument,
|
||||
FriendModel,
|
||||
} from '../../../models/user/friend';
|
||||
import { TcService, TcDbService, TcContext } from 'tailchat-server-sdk';
|
||||
import { isNil } from 'lodash';
|
||||
|
||||
interface FriendService
|
||||
extends TcService,
|
||||
TcDbService<FriendDocument, FriendModel> {}
|
||||
class FriendService extends TcService {
|
||||
get serviceName(): string {
|
||||
return 'friend';
|
||||
}
|
||||
onInit(): void {
|
||||
this.registerLocalDb(require('../../../models/user/friend').default);
|
||||
// this.registerMixin(TcCacheCleaner(['cache.clean.friend']));
|
||||
|
||||
this.registerAction('getAllFriends', this.getAllFriends);
|
||||
this.registerAction('buildFriendRelation', this.buildFriendRelation, {
|
||||
params: {
|
||||
user1: 'string',
|
||||
user2: 'string',
|
||||
},
|
||||
});
|
||||
this.registerAction('removeFriend', this.removeFriend, {
|
||||
params: {
|
||||
friendUserId: 'string',
|
||||
},
|
||||
});
|
||||
this.registerAction('checkIsFriend', this.checkIsFriend, {
|
||||
params: {
|
||||
targetId: 'string',
|
||||
},
|
||||
});
|
||||
this.registerAction('setFriendNickname', this.setFriendNickname, {
|
||||
params: {
|
||||
targetId: 'string',
|
||||
nickname: 'string',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有好友
|
||||
*/
|
||||
async getAllFriends(ctx: TcContext<{}>) {
|
||||
const userId = ctx.meta.userId;
|
||||
|
||||
const list = await this.adapter.find({
|
||||
query: {
|
||||
from: userId,
|
||||
},
|
||||
});
|
||||
|
||||
const records: Friend[] = await this.transformDocuments(ctx, {}, list);
|
||||
const res = records.map((r) => ({
|
||||
id: r.to,
|
||||
nickname: r.nickname,
|
||||
}));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建好友关系
|
||||
*/
|
||||
async buildFriendRelation(ctx: TcContext<{ user1: string; user2: string }>) {
|
||||
const { user1, user2 } = ctx.params;
|
||||
await this.adapter.model.buildFriendRelation(user1, user2);
|
||||
|
||||
this.unicastNotify(ctx, user1, 'add', {
|
||||
userId: user2,
|
||||
});
|
||||
this.unicastNotify(ctx, user2, 'add', {
|
||||
userId: user1,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除单项好友关系
|
||||
*/
|
||||
async removeFriend(ctx: TcContext<{ friendUserId: string }>) {
|
||||
const { friendUserId } = ctx.params;
|
||||
const { userId } = ctx.meta;
|
||||
|
||||
await this.adapter.model.findOneAndRemove({
|
||||
from: userId,
|
||||
to: friendUserId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查对方是否为自己好友
|
||||
*/
|
||||
async checkIsFriend(ctx: TcContext<{ targetId: string }>) {
|
||||
const { targetId } = ctx.params;
|
||||
const userId = ctx.meta.userId;
|
||||
|
||||
const isFriend = await this.adapter.model.exists({
|
||||
from: userId,
|
||||
to: targetId,
|
||||
});
|
||||
|
||||
return isFriend;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置好友昵称
|
||||
*/
|
||||
async setFriendNickname(
|
||||
ctx: TcContext<{ targetId: string; nickname: string }>
|
||||
) {
|
||||
const { targetId, nickname } = ctx.params;
|
||||
const userId = ctx.meta.userId;
|
||||
const t = ctx.meta.t;
|
||||
|
||||
const res = await this.adapter.model.findOneAndUpdate(
|
||||
{
|
||||
from: userId,
|
||||
to: targetId,
|
||||
},
|
||||
{
|
||||
nickname: nickname,
|
||||
}
|
||||
);
|
||||
|
||||
if (isNil(res)) {
|
||||
throw new Error(t('设置昵称失败, 没有找到好友关系信息'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
export default FriendService;
|
||||
190
server/services/core/user/friendRequest.service.ts
Normal file
190
server/services/core/user/friendRequest.service.ts
Normal file
@@ -0,0 +1,190 @@
|
||||
import {
|
||||
TcService,
|
||||
TcDbService,
|
||||
TcContext,
|
||||
Errors,
|
||||
DataNotFoundError,
|
||||
NoPermissionError,
|
||||
config,
|
||||
} from 'tailchat-server-sdk';
|
||||
import _ from 'lodash';
|
||||
import type { FriendRequest } from '../../../models/user/friendRequest';
|
||||
|
||||
interface FriendService extends TcService, TcDbService<any> {}
|
||||
class FriendService extends TcService {
|
||||
get serviceName(): string {
|
||||
return 'friend.request';
|
||||
}
|
||||
onInit(): void {
|
||||
this.registerLocalDb(require('../../../models/user/friendRequest').default);
|
||||
// this.registerMixin(TcCacheCleaner(['cache.clean.friend']));
|
||||
|
||||
this.registerAction('add', this.add, {
|
||||
params: {
|
||||
to: 'string',
|
||||
message: [{ type: 'string', optional: true }],
|
||||
},
|
||||
});
|
||||
this.registerAction('allRelated', this.allRelated);
|
||||
this.registerAction('accept', this.accept, {
|
||||
params: {
|
||||
requestId: 'string',
|
||||
},
|
||||
});
|
||||
this.registerAction('deny', this.deny, {
|
||||
params: {
|
||||
requestId: 'string',
|
||||
},
|
||||
});
|
||||
this.registerAction('cancel', this.cancel, {
|
||||
params: {
|
||||
requestId: 'string',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求添加好友
|
||||
*/
|
||||
async add(ctx: TcContext<{ to: string; message?: string }>) {
|
||||
const from = ctx.meta.userId;
|
||||
const t = ctx.meta.t;
|
||||
|
||||
const { to, message } = ctx.params;
|
||||
|
||||
if (config.feature.disableAddFriend === true) {
|
||||
throw new NoPermissionError(t('管理员禁止添加好友功能'));
|
||||
}
|
||||
|
||||
if (from === to) {
|
||||
throw new Errors.MoleculerError(t('不能添加自己为好友'));
|
||||
}
|
||||
|
||||
const exist = await this.adapter.findOne({
|
||||
from,
|
||||
to,
|
||||
});
|
||||
if (exist) {
|
||||
throw new Errors.MoleculerError(t('不能发送重复的好友请求'));
|
||||
}
|
||||
|
||||
const isFriend = await ctx.call('friend.checkIsFriend', { targetId: to });
|
||||
if (isFriend) {
|
||||
throw new Error(t('对方已经是您的好友, 不能再次添加'));
|
||||
}
|
||||
|
||||
const doc = await this.adapter.insert({
|
||||
from,
|
||||
to,
|
||||
message,
|
||||
});
|
||||
const request = await this.transformDocuments(ctx, {}, doc);
|
||||
|
||||
this.listcastNotify(ctx, [from, to], 'add', request);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有与自己相关的好友请求
|
||||
*/
|
||||
async allRelated(ctx: TcContext) {
|
||||
const userId = ctx.meta.userId;
|
||||
|
||||
const doc = await this.adapter.find({
|
||||
query: {
|
||||
$or: [{ from: userId }, { to: userId }],
|
||||
},
|
||||
});
|
||||
|
||||
const list = await await this.transformDocuments(ctx, {}, doc);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 接受好友请求
|
||||
*/
|
||||
async accept(ctx: TcContext<{ requestId: string }>) {
|
||||
const requestId = ctx.params.requestId;
|
||||
|
||||
const request: FriendRequest = await this.adapter.findById(requestId);
|
||||
if (_.isNil(request)) {
|
||||
throw new DataNotFoundError('该好友请求未找到');
|
||||
}
|
||||
|
||||
if (ctx.meta.userId !== String(request.to)) {
|
||||
throw new NoPermissionError();
|
||||
}
|
||||
|
||||
await ctx.call('friend.buildFriendRelation', {
|
||||
user1: String(request.from),
|
||||
user2: String(request.to),
|
||||
});
|
||||
|
||||
await this.adapter.removeById(request._id);
|
||||
|
||||
this.listcastNotify(
|
||||
ctx,
|
||||
[String(request.from), String(request.to)],
|
||||
'remove',
|
||||
{
|
||||
requestId,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 拒绝好友请求
|
||||
*/
|
||||
async deny(ctx: TcContext<{ requestId: string }>) {
|
||||
const requestId = ctx.params.requestId;
|
||||
|
||||
const request: FriendRequest = await this.adapter.findById(requestId);
|
||||
if (_.isNil(request)) {
|
||||
throw new DataNotFoundError('该好友请求未找到');
|
||||
}
|
||||
|
||||
if (ctx.meta.userId !== String(request.to)) {
|
||||
throw new NoPermissionError();
|
||||
}
|
||||
|
||||
await this.adapter.removeById(request._id);
|
||||
|
||||
this.listcastNotify(
|
||||
ctx,
|
||||
[String(request.from), String(request.to)],
|
||||
'remove',
|
||||
{
|
||||
requestId,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消好友请求
|
||||
*/
|
||||
async cancel(ctx: TcContext<{ requestId: string }>) {
|
||||
const requestId = ctx.params.requestId;
|
||||
|
||||
const request: FriendRequest = await this.adapter.findById(requestId);
|
||||
if (_.isNil(request)) {
|
||||
throw new DataNotFoundError('该好友请求未找到');
|
||||
}
|
||||
|
||||
if (ctx.meta.userId !== String(request.from)) {
|
||||
throw new NoPermissionError();
|
||||
}
|
||||
|
||||
await this.adapter.removeById(request._id);
|
||||
|
||||
this.listcastNotify(
|
||||
ctx,
|
||||
[String(request.from), String(request.to)],
|
||||
'remove',
|
||||
{
|
||||
requestId,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
export default FriendService;
|
||||
76
server/services/core/user/mail.service.ts
Normal file
76
server/services/core/user/mail.service.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import type { MailDocument, MailModel } from '../../../models/user/mail';
|
||||
import { TcService, TcContext, TcDbService } from 'tailchat-server-sdk';
|
||||
import ejs from 'ejs';
|
||||
import path from 'path';
|
||||
|
||||
interface MailService extends TcService, TcDbService<MailDocument, MailModel> {}
|
||||
class MailService extends TcService {
|
||||
smtpServiceAvailable = false;
|
||||
|
||||
get serviceName(): string {
|
||||
return 'mail';
|
||||
}
|
||||
|
||||
onInit(): void {
|
||||
this.registerLocalDb(require('../../../models/user/mail').default);
|
||||
|
||||
this.registerAction('sendMail', this.sendMail, {
|
||||
visibility: 'public',
|
||||
params: {
|
||||
to: 'string',
|
||||
subject: 'string',
|
||||
html: 'string',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
onInited() {
|
||||
this.adapter.model.verifyMailService().then((available) => {
|
||||
if (available) {
|
||||
this.logger.info('SMTP 服务可用');
|
||||
} else {
|
||||
this.logger.warn('SMTP 服务不可用');
|
||||
}
|
||||
|
||||
this.smtpServiceAvailable = available;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送邮件
|
||||
*/
|
||||
async sendMail(
|
||||
ctx: TcContext<{
|
||||
to: string;
|
||||
subject: string;
|
||||
html: string;
|
||||
}>
|
||||
) {
|
||||
if (!this.smtpServiceAvailable) {
|
||||
throw new Error('SMTP 服务不可用');
|
||||
}
|
||||
|
||||
const { to, subject, html } = ctx.params;
|
||||
const { t } = ctx.meta;
|
||||
|
||||
try {
|
||||
const info = await this.adapter.model.sendMail({
|
||||
to,
|
||||
subject,
|
||||
html: await ejs.renderFile(
|
||||
path.resolve(__dirname, '../../../views/mail.ejs'),
|
||||
{
|
||||
body: html,
|
||||
}
|
||||
),
|
||||
});
|
||||
|
||||
this.logger.info('sendMailSuccess:', info);
|
||||
} catch (err) {
|
||||
this.logger.error('sendMailFailed:', err);
|
||||
throw new Error(t('邮件发送失败'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default MailService;
|
||||
1279
server/services/core/user/user.service.ts
Normal file
1279
server/services/core/user/user.service.ts
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user