163 lines
4.5 KiB
Go
163 lines
4.5 KiB
Go
// Package app1hdl 是小程序 app1 的 HTTP 接入层。
|
|
package app1hdl
|
|
|
|
import (
|
|
"strconv"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"portal-mini-go/internal/middleware"
|
|
"portal-mini-go/internal/model"
|
|
"portal-mini-go/internal/pkg/errors"
|
|
"portal-mini-go/internal/pkg/response"
|
|
"portal-mini-go/internal/pkg/types"
|
|
app1svc "portal-mini-go/internal/service/miniapp/app1"
|
|
)
|
|
|
|
// Handler app1 请求处理。
|
|
type Handler struct {
|
|
svc *app1svc.Service
|
|
}
|
|
|
|
func NewHandler(svc *app1svc.Service) *Handler { return &Handler{svc: svc} }
|
|
|
|
type LoginReq struct {
|
|
Code string `json:"code" binding:"required"`
|
|
}
|
|
|
|
// Login 处理小程序登录请求。app_id 由 MiniAppAuth 中间件从请求头校验并注入。
|
|
func (h *Handler) Login(c *gin.Context) {
|
|
var req LoginReq
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.Error(errors.ErrBadRequest)
|
|
return
|
|
}
|
|
appID := middleware.AppID(c)
|
|
token, u, err := h.svc.Login(c.Request.Context(), appID, req.Code)
|
|
if err != nil {
|
|
c.Error(err)
|
|
return
|
|
}
|
|
response.OK(c, gin.H{"token": token, "user": toProfileView(u)})
|
|
}
|
|
|
|
// Logout 注销当前用户会话。需在用户会话中间件通过后调用。
|
|
func (h *Handler) Logout(c *gin.Context) {
|
|
if err := h.svc.Logout(c.Request.Context(), middleware.SessionToken(c)); err != nil {
|
|
c.Error(err)
|
|
return
|
|
}
|
|
response.OK(c, nil)
|
|
}
|
|
|
|
// Profile 获取当前登录用户资料。
|
|
func (h *Handler) Profile(c *gin.Context) {
|
|
u, err := h.svc.GetProfile(c.Request.Context(), middleware.MiniID(c), middleware.UserID(c))
|
|
if err != nil {
|
|
c.Error(err)
|
|
return
|
|
}
|
|
response.OK(c, toProfileView(u))
|
|
}
|
|
|
|
type UpdateProfileReq struct {
|
|
Nickname string `json:"nickname"`
|
|
Avatar string `json:"avatar"`
|
|
}
|
|
|
|
// UpdateProfile 更新当前登录用户的昵称/头像,留空字段不更新。
|
|
func (h *Handler) UpdateProfile(c *gin.Context) {
|
|
var req UpdateProfileReq
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.Error(errors.ErrBadRequest)
|
|
return
|
|
}
|
|
if err := h.svc.UpdateProfile(c.Request.Context(), middleware.MiniID(c), middleware.UserID(c), req.Nickname, req.Avatar); err != nil {
|
|
c.Error(err)
|
|
return
|
|
}
|
|
response.OK(c, nil)
|
|
}
|
|
|
|
// GetUser 获取同小程序下指定用户(仅公开字段)。
|
|
func (h *Handler) GetUser(c *gin.Context) {
|
|
id, ok := parseUserID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
u, err := h.svc.GetUser(c.Request.Context(), middleware.MiniID(c), id)
|
|
if err != nil {
|
|
c.Error(err)
|
|
return
|
|
}
|
|
response.OK(c, toPublicUserView(u))
|
|
}
|
|
|
|
// ListUsers 分页列出同小程序下的用户。
|
|
func (h *Handler) ListUsers(c *gin.Context) {
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
|
|
list, total, err := h.svc.ListUsers(c.Request.Context(), middleware.MiniID(c), page, size)
|
|
if err != nil {
|
|
c.Error(err)
|
|
return
|
|
}
|
|
views := make([]PublicUserView, 0, len(list))
|
|
for i := range list {
|
|
views = append(views, toPublicUserView(&list[i]))
|
|
}
|
|
response.OK(c, gin.H{"list": views, "total": total, "page": page, "size": size})
|
|
}
|
|
|
|
// ProfileView 当前用户自身的资料视图(含自身 openid/unionid)。
|
|
type ProfileView struct {
|
|
ID uint64 `json:"id"`
|
|
OpenID string `json:"openid"`
|
|
UnionID string `json:"union_id"`
|
|
Nickname string `json:"nickname"`
|
|
Avatar string `json:"avatar"`
|
|
CreatedAt types.Time `json:"created_at"`
|
|
}
|
|
|
|
// PublicUserView 对外的用户公开视图,剔除 openid/unionid 等敏感字段。
|
|
type PublicUserView struct {
|
|
ID uint64 `json:"id"`
|
|
Nickname string `json:"nickname"`
|
|
Avatar string `json:"avatar"`
|
|
}
|
|
|
|
func toProfileView(u *model.User) ProfileView {
|
|
return ProfileView{
|
|
ID: u.ID,
|
|
OpenID: u.OpenID,
|
|
UnionID: u.UnionID,
|
|
Nickname: u.Nickname,
|
|
Avatar: u.Avatar,
|
|
CreatedAt: u.CreatedAt,
|
|
}
|
|
}
|
|
|
|
func toPublicUserView(u *model.User) PublicUserView {
|
|
return PublicUserView{ID: u.ID, Nickname: u.Nickname, Avatar: u.Avatar}
|
|
}
|
|
|
|
func parseUserID(c *gin.Context) (uint64, bool) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
c.Error(errors.ErrBadRequest)
|
|
return 0, false
|
|
}
|
|
return id, true
|
|
}
|
|
|
|
// Register 注册 app1 的路由。g 已带 /api/ma 前缀与 MiniAppAuth 中间件(校验请求头 app_id)。
|
|
// userAuth 为用户会话中间件,用于保护需要登录态的接口。
|
|
func Register(g *gin.RouterGroup, h *Handler, userAuth gin.HandlerFunc) {
|
|
g.POST("/login", h.Login)
|
|
g.POST("/logout", userAuth, h.Logout)
|
|
g.GET("/profile", userAuth, h.Profile)
|
|
g.PUT("/profile", userAuth, h.UpdateProfile)
|
|
g.GET("/users/:id", userAuth, h.GetUser)
|
|
g.GET("/users", userAuth, h.ListUsers)
|
|
}
|