Skip to content

Commit 7bb151e

Browse files
authored
Merge pull request #106 from import-ai/feat/wechat
feat(wechat): support wechat login
2 parents d636ca4 + b906f50 commit 7bb151e

24 files changed

+532
-43
lines changed

.env.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,9 @@ OBB_MEILI_KEY=meili_master_key
2424
OBB_OPENAI_URL=https://api.openai.com/v1
2525
OBB_OPENAI_KEY=***
2626
OBB_OPENAI_EMBEDDING_MODEL=text-embedding-v1
27+
28+
OBB_WECHAT_APP_ID=
29+
OBB_WECHAT_APP_SECRET=
30+
OBB_OPEN_WECHAT_APP_ID=
31+
OBB_OPEN_WECHAT_APP_SECRET=
32+
OBB_WECHAT_REDIRECT_URI=

README.md

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,50 @@
11
# OmniBox Backend
22

3+
## Project Introduction
4+
5+
OmniBox Backend is a backend service developed based on the NestJS framework, providing user authentication, file management, conversation management, and other functionalities.
6+
7+
## Main Features
8+
9+
### File Management
10+
11+
- Supports file upload, download, and management
12+
- Integrated MinIO object storage
13+
14+
### Conversation Management
15+
16+
- Supports multi-user conversations
17+
- Message history records
18+
19+
### Permission Management
20+
21+
- Namespace-based permission control
22+
- User group management
23+
- Resource permission allocation
24+
325
## Dev
426

527
### Docker
628

7-
+ Watch & Debug mode
29+
- Watch & Debug mode
830

931
```shell
1032
docker compose -f base.yaml -f dev.yaml up -d
1133
```
1234

13-
+ Build mode
35+
- Build mode
1436

1537
```shell
1638
docker compose -f base.yaml -f build.yaml up -d --build
1739
```
1840

19-
+ Run with persistence postgres and minio data
41+
- Run with persistence postgres and minio data
2042

2143
```shell
2244
docker compose ... -f persistence.yaml ...
2345
```
2446

25-
+ Run with pgadmin
47+
- Run with pgadmin
2648

2749
```shell
2850
docker compose ... -f pgadmin.yaml ...
@@ -31,7 +53,7 @@
3153
Then login with:
3254

3355
| Name | Value |
34-
|----------|------------------|
56+
| -------- | ---------------- |
3557
| Username | `omnibox@qq.com` |
3658
| Password | `Passw0rd` |
3759

@@ -50,3 +72,12 @@ $ pnpm run start:dev
5072
# Production mode
5173
$ pnpm run start:prod
5274
```
75+
76+
## Tech Stack
77+
78+
- **Framework**: NestJS
79+
- **Database**: PostgreSQL + TypeORM
80+
- **Object Storage**: MinIO
81+
- **Authentication**: JWT + Passport
82+
- **Email Service**: Nodemailer
83+
- **Search**: Meilisearch

package-lock.json

Lines changed: 11 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/app.module.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ import { SearchModule } from 'src/search/search.module';
2222
import { InvitationsModule } from 'src/invitations/invitations.module';
2323
import { LoggerMiddleware } from './logger.middleware';
2424
import { UserOptions1751904560034 } from 'src/migrations/1751904560034-user-options';
25+
import { UserBindings1752652489640 } from 'src/migrations/1752652489640-user-bindings.ts';
2526
import { Tags1751905414493 } from 'src/migrations/1751905414493-tags';
2627
import { Init1751900000000 } from 'src/migrations/1751900000000-init';
2728
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
29+
import { NullUserEmail1752814358259 } from 'src/migrations/1752814358259-null-user-email';
2830

2931
@Module({
3032
controllers: [AppController],
@@ -80,8 +82,10 @@ import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
8082
maxQueryExecutionTime: config.get('OBB_DB_EXEC_TIME', 0),
8183
migrations: [
8284
Init1751900000000,
83-
UserOptions1751904560034,
8485
Tags1751905414493,
86+
UserOptions1751904560034,
87+
UserBindings1752652489640,
88+
NullUserEmail1752814358259,
8589
],
8690
migrationsRun: true,
8791
namingStrategy: new SnakeNamingStrategy(),

src/auth/auth.controller.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ export class AuthController {
2020
@Public()
2121
@Post('login')
2222
@HttpCode(200)
23-
async login(@Request() req) {
24-
return await this.authService.login(req.user.email);
23+
login(@Request() req) {
24+
return this.authService.login(req.user);
2525
}
2626

2727
@Public()

src/auth/auth.module.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@ import { InternalAuthController } from 'src/auth/internal.auth.controller';
1414
import { NamespacesModule } from 'src/namespaces/namespaces.module';
1515
import { GroupsModule } from 'src/groups/groups.module';
1616
import { PermissionsModule } from 'src/permissions/permissions.module';
17+
import { WechatService } from 'src/auth/wechat.service';
18+
import { WechatController } from 'src/auth/wechat.controller';
1719

1820
@Module({
19-
exports: [AuthService],
20-
controllers: [AuthController, InternalAuthController],
21+
exports: [AuthService, WechatService],
22+
controllers: [AuthController, InternalAuthController, WechatController],
2123
providers: [
2224
AuthService,
25+
WechatService,
2326
JwtStrategy,
2427
LocalStrategy,
2528
{

src/auth/auth.service.ts

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { DataSource, EntityManager } from 'typeorm';
21
import { JwtService } from '@nestjs/jwt';
2+
import { User } from 'src/user/entities/user.entity';
3+
import { DataSource, EntityManager } from 'typeorm';
34
import { MailService } from 'src/mail/mail.service';
45
import { UserService } from 'src/user/user.service';
56
import { NamespacesService } from 'src/namespaces/namespaces.service';
@@ -46,19 +47,12 @@ export class AuthService {
4647
};
4748
}
4849

49-
async login(email: string) {
50-
const account = await this.userService.findByEmail(email);
51-
if (!account) {
52-
throw new BadRequestException('User not found');
53-
}
54-
const payload: LoginPayloadDto = {
55-
email: account.email,
56-
sub: account.id,
57-
};
50+
login(user: User) {
5851
return {
59-
id: account.id,
60-
username: account.username,
61-
access_token: this.jwtService.sign(payload),
52+
id: user.id,
53+
access_token: this.jwtService.sign({
54+
sub: user.id,
55+
}),
6256
};
6357
}
6458

@@ -114,10 +108,8 @@ export class AuthService {
114108
}
115109
return {
116110
id: user.id,
117-
username: user.username,
118111
access_token: this.jwtService.sign({
119112
sub: user.id,
120-
email: user.email,
121113
}),
122114
};
123115
});
@@ -133,12 +125,12 @@ export class AuthService {
133125
if (!user) {
134126
throw new NotFoundException('User not found.');
135127
}
136-
const payload: LoginPayloadDto = { email: user.email, sub: user.id };
128+
const payload: LoginPayloadDto = { email: user.email!, sub: user.id };
137129
const token = this.jwtService.sign(payload, {
138130
expiresIn: '1h',
139131
});
140132
const mailSendUri = `${url}?token=${token}`;
141-
await this.mailService.sendPasswordEmail(user.email, mailSendUri);
133+
await this.mailService.sendPasswordEmail(user.email!, mailSendUri);
142134
// return { url: mailSendUri };
143135
}
144136

src/auth/dto/wechat-login.dto.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { IsString } from 'class-validator';
2+
3+
export class WechatCheckResponseDto {
4+
@IsString()
5+
status: 'pending' | 'success' | 'expired';
6+
7+
user?: {
8+
id: string;
9+
access_token: string;
10+
};
11+
}

src/auth/wechat.controller.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { WechatService } from './wechat.service';
2+
import { Public } from 'src/auth/decorators/public.decorator';
3+
import { Get, Query, Controller } from '@nestjs/common';
4+
5+
@Controller('api/v1/wechat')
6+
export class WechatController {
7+
constructor(private readonly wechatService: WechatService) {}
8+
9+
@Public()
10+
@Get('qrcode')
11+
getQrCode() {
12+
return this.wechatService.getQrCodeParams();
13+
}
14+
15+
@Public()
16+
@Get('callback')
17+
async handleCallback(
18+
@Query('code') code: string,
19+
@Query('state') state: string,
20+
) {
21+
return await this.wechatService.handleCallback(code, state);
22+
}
23+
24+
@Public()
25+
@Get('auth-url')
26+
getAuthUrl() {
27+
return this.wechatService.getWechatAuthUrl();
28+
}
29+
}

0 commit comments

Comments
 (0)