2 Commits

6 changed files with 73 additions and 3 deletions

View File

@@ -11,6 +11,7 @@ import { ChannelsModule } from './channels/channels.module';
import { MessagingModule } from './messaging/messaging.module';
import { EventsModule } from './events/events.module';
import { RealtimeModule } from './realtime/realtime.module';
import { MembersModule } from './members/members.module';
@Module({
imports: [
@@ -19,6 +20,7 @@ import { RealtimeModule } from './realtime/realtime.module';
RealtimeModule,
GuildsModule,
ChannelsModule,
MembersModule,
MessagingModule,
],
controllers: [HealthController, MetricsController],

View File

@@ -1,4 +1,4 @@
import { Injectable } from '@nestjs/common';
import { BadRequestException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Channel } from '../entities/channel.entity';
@@ -26,9 +26,14 @@ export class ChannelsService {
}
create(input: Partial<Channel>) {
const guildId = String(input.guildId ?? '').trim();
const name = String(input.name ?? '').trim();
if (!guildId) throw new BadRequestException('guildId is required');
if (!name) throw new BadRequestException('name is required');
const channel = this.channelRepo.create({
guildId: String(input.guildId ?? ''),
name: String(input.name ?? ''),
guildId,
name,
kind: input.kind === 'announcement' ? 'announcement' : 'text',
isPrivate: Boolean(input.isPrivate),
lastSeq: 0,

View File

@@ -24,6 +24,23 @@ async function bootstrap() {
validateEnv();
const app = await NestFactory.create(AppModule);
const corsOrigins = (process.env.FABRIC_BACKEND_GUILD_CORS_ORIGINS ?? '')
.split(',')
.map((x) => x.trim())
.filter(Boolean);
app.enableCors({
origin: (origin, callback) => {
if (!origin) return callback(null, true);
if (origin === 'null') return callback(null, true);
if (!corsOrigins.length) return callback(null, true);
if (corsOrigins.includes(origin)) return callback(null, true);
return callback(new Error('CORS origin not allowed'), false);
},
methods: ['GET', 'POST', 'PATCH', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'x-client-name', 'x-request-id', 'x-api-key'],
credentials: false,
});
app.setGlobalPrefix('api');
const metrics = app.get(MetricsService);
app.use(createRequestContextMiddleware('guild', metrics));

View File

@@ -0,0 +1,13 @@
import { Controller, Get, Query } from '@nestjs/common';
import { MembersService } from './members.service';
@Controller('members')
export class MembersController {
constructor(private readonly membersService: MembersService) {}
@Get()
list(@Query('guildId') guildId?: string) {
return this.membersService.list(guildId);
}
}

View File

@@ -0,0 +1,13 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { GuildMember } from '../entities/guild-member.entity';
import { MembersController } from './members.controller';
import { MembersService } from './members.service';
@Module({
imports: [TypeOrmModule.forFeature([GuildMember])],
controllers: [MembersController],
providers: [MembersService],
})
export class MembersModule {}

View File

@@ -0,0 +1,20 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { GuildMember } from '../entities/guild-member.entity';
@Injectable()
export class MembersService {
constructor(
@InjectRepository(GuildMember)
private readonly memberRepo: Repository<GuildMember>,
) {}
list(guildId?: string) {
if (guildId) {
return this.memberRepo.find({ where: { guildId, status: 'active' }, order: { createdAt: 'ASC' }, take: 500 });
}
return this.memberRepo.find({ where: { status: 'active' }, order: { createdAt: 'ASC' }, take: 500 });
}
}