Files
zhiyin/backend/src/modules/user/user.controller.ts
T
yuzhiran 04b30d0024 feat(backend): record lastLoginAt/IP/location on every login
Add lastLoginAt, lastLoginIp, lastLoginLocation to User schema. recordLogin() method called from all 5 login flows (phone, email, wx, password, register). Exposed in safeUser so info endpoint returns login metadata.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-06-22 12:38:07 +08:00

92 lines
2.8 KiB
TypeScript

import { Controller, Post, Get, Put, Body, Req, HttpCode, HttpStatus, UseGuards } from '@nestjs/common'
import { UserService } from './user.service'
import { Public } from '../../common/decorators/public.decorator'
import { CurrentUser } from '../../common/decorators/current-user.decorator'
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard'
@Controller('user')
export class UserController {
constructor(private userService: UserService) {}
@Public()
@Post('send-code')
@HttpCode(HttpStatus.OK)
async sendCode(@Body('phone') phone: string) {
return this.userService.sendCode(phone)
}
@Public()
@Post('login')
@HttpCode(HttpStatus.OK)
async login(@Body('phone') phone: string, @Body('code') code: string, @Req() req) {
return this.userService.loginByPhone(phone, code, req.ip)
}
// 📧 邮箱验证码登录(H5 用)
@Public()
@Post('send-email-code')
@HttpCode(HttpStatus.OK)
async sendEmailCode(@Body('email') email: string) {
return this.userService.sendEmailCode(email)
}
/** 绑定微信 openid 到当前登录用户 */
@UseGuards(JwtAuthGuard)
@Post('bind-wx')
@HttpCode(HttpStatus.OK)
async bindWx(@CurrentUser('userId') userId: string, @Body('code') code: string) {
return this.userService.bindWxOpenid(userId, code)
}
@Public()
@Post('email-login')
@HttpCode(HttpStatus.OK)
async emailLogin(@Body('email') email: string, @Body('code') code: string, @Req() req) {
return this.userService.loginByEmail(email, code, req.ip)
}
// 密码登录
@Public()
@Post('password-login')
@HttpCode(HttpStatus.OK)
async passwordLogin(@Body('email') email: string, @Body('password') password: string, @Req() req) {
return this.userService.loginByPassword(email, password, req.ip)
}
// 邮箱+密码注册
@Public()
@Post('register')
@HttpCode(HttpStatus.OK)
async register(@Body('email') email: string, @Body('password') password: string, @Req() req) {
return this.userService.registerWithPassword(email, password, req.ip)
}
// 微信静默登录
@Public()
@Post('wx-login')
@HttpCode(HttpStatus.OK)
async wxLogin(@Body('code') code: string, @Req() req) {
return this.userService.loginByWx(code, undefined, req.ip)
}
@Get('info')
async getInfo(@CurrentUser('userId') userId: string) {
return this.userService.getInfo(userId)
}
@Put('update')
async update(@CurrentUser('userId') userId: string, @Body() data: { nickname?: string; avatar?: string }) {
return this.userService.update(userId, data)
}
@Get('usage')
async getUsage(@CurrentUser('userId') userId: string) {
return this.userService.getUsage(userId)
}
@Post('set-password')
async setPassword(@CurrentUser('userId') userId: string, @Body('password') password: string) {
return this.userService.setPassword(userId, password)
}
}