205 lines
5.3 KiB
Go
205 lines
5.3 KiB
Go
package http
|
|
|
|
import (
|
|
"chatapp3-golang/internal/config"
|
|
"chatapp3-golang/internal/integration"
|
|
"chatapp3-golang/internal/repo"
|
|
"chatapp3-golang/internal/service"
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
const authUserContextKey = "auth_user"
|
|
|
|
func NewRouter(
|
|
cfg config.Config,
|
|
repository *repo.Repository,
|
|
javaClient *integration.Client,
|
|
inviteService *service.InviteService,
|
|
baishunService *service.BaishunService,
|
|
) *gin.Engine {
|
|
router := gin.New()
|
|
router.Use(gin.Logger(), gin.Recovery())
|
|
|
|
router.GET("/health", func(c *gin.Context) {
|
|
ctx, cancel := context.WithTimeout(c.Request.Context(), cfg.Timeout)
|
|
defer cancel()
|
|
if err := repository.Ping(ctx); err != nil {
|
|
c.JSON(http.StatusServiceUnavailable, gin.H{
|
|
"code": "dependency_unavailable",
|
|
"message": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"code": "ok", "message": "success1"})
|
|
})
|
|
|
|
router.GET("/public/h5/invite-campaign/landing", func(c *gin.Context) {
|
|
resp, err := inviteService.GetLanding(c.Request.Context(), c.Query("code"))
|
|
if err != nil {
|
|
writeError(c, err)
|
|
return
|
|
}
|
|
writeOK(c, resp)
|
|
})
|
|
|
|
internal := router.Group("/internal/invite-campaign")
|
|
internal.POST("/recharge-success", func(c *gin.Context) {
|
|
var req service.RechargeSuccessRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
writeError(c, service.NewAppError(http.StatusBadRequest, "bad_request", err.Error()))
|
|
return
|
|
}
|
|
resp, err := inviteService.HandleRechargeSuccess(c.Request.Context(), req)
|
|
if err != nil {
|
|
writeError(c, err)
|
|
return
|
|
}
|
|
writeOK(c, resp)
|
|
})
|
|
|
|
authenticated := router.Group("/app/h5/invite-campaign")
|
|
authenticated.Use(authMiddleware(javaClient))
|
|
authenticated.GET("/home", func(c *gin.Context) {
|
|
user := mustAuthUser(c)
|
|
resp, err := inviteService.GetHome(c.Request.Context(), user)
|
|
if err != nil {
|
|
writeError(c, err)
|
|
return
|
|
}
|
|
writeOK(c, resp)
|
|
})
|
|
authenticated.POST("/bind-code", func(c *gin.Context) {
|
|
user := mustAuthUser(c)
|
|
var req service.BindCodeRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
writeError(c, service.NewAppError(http.StatusBadRequest, "bad_request", err.Error()))
|
|
return
|
|
}
|
|
resp, err := inviteService.BindCode(c.Request.Context(), user, resolveClientIP(c), req)
|
|
if err != nil {
|
|
writeError(c, err)
|
|
return
|
|
}
|
|
writeOK(c, resp)
|
|
})
|
|
authenticated.POST("/tasks/claim", func(c *gin.Context) {
|
|
user := mustAuthUser(c)
|
|
var req service.TaskClaimRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
writeError(c, service.NewAppError(http.StatusBadRequest, "bad_request", err.Error()))
|
|
return
|
|
}
|
|
resp, err := inviteService.ClaimTask(c.Request.Context(), user, req)
|
|
if err != nil {
|
|
writeError(c, err)
|
|
return
|
|
}
|
|
writeOK(c, resp)
|
|
})
|
|
|
|
registerBaishunRoutes(router, cfg, javaClient, baishunService)
|
|
|
|
return router
|
|
}
|
|
|
|
func authMiddleware(javaClient *integration.Client) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
authorization := strings.TrimSpace(c.GetHeader("Authorization"))
|
|
if authorization == "" {
|
|
writeError(c, service.NewAppError(http.StatusUnauthorized, "missing_authorization", "authorization is required"))
|
|
c.Abort()
|
|
return
|
|
}
|
|
token := trimBearer(authorization)
|
|
ctx, cancel := context.WithTimeout(c.Request.Context(), 10*time.Second)
|
|
defer cancel()
|
|
credential, err := javaClient.AuthenticateToken(ctx, token)
|
|
if err != nil {
|
|
writeError(c, service.NewAppError(http.StatusUnauthorized, "invalid_token", err.Error()))
|
|
c.Abort()
|
|
return
|
|
}
|
|
c.Set(authUserContextKey, service.AuthUser{
|
|
UserID: int64(credential.UserID),
|
|
SysOrigin: credential.SysOrigin,
|
|
Token: token,
|
|
Authorization: authorization,
|
|
})
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
func mustAuthUser(c *gin.Context) service.AuthUser {
|
|
value, exists := c.Get(authUserContextKey)
|
|
if !exists {
|
|
return service.AuthUser{}
|
|
}
|
|
user, _ := value.(service.AuthUser)
|
|
return user
|
|
}
|
|
|
|
func writeOK(c *gin.Context, data any) {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"status": true,
|
|
"errorCode": 0,
|
|
"errorMsg": "success",
|
|
"body": data,
|
|
"code": "success",
|
|
"message": "success",
|
|
"data": data,
|
|
"time": time.Now().UnixMilli(),
|
|
})
|
|
}
|
|
|
|
func writeError(c *gin.Context, err error) {
|
|
var appErr *service.AppError
|
|
if errors.As(err, &appErr) {
|
|
c.JSON(appErr.Status, gin.H{
|
|
"status": false,
|
|
"errorCode": appErr.Status,
|
|
"errorCodeName": appErr.Code,
|
|
"errorMsg": appErr.Message,
|
|
"body": nil,
|
|
"code": appErr.Code,
|
|
"message": appErr.Message,
|
|
"data": nil,
|
|
"time": time.Now().UnixMilli(),
|
|
})
|
|
return
|
|
}
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"status": false,
|
|
"errorCode": http.StatusInternalServerError,
|
|
"errorCodeName": "internal_error",
|
|
"errorMsg": err.Error(),
|
|
"body": nil,
|
|
"code": "internal_error",
|
|
"message": err.Error(),
|
|
"data": nil,
|
|
"time": time.Now().UnixMilli(),
|
|
})
|
|
}
|
|
|
|
func trimBearer(authorization string) string {
|
|
if strings.HasPrefix(strings.ToLower(authorization), "bearer ") {
|
|
return strings.TrimSpace(authorization[7:])
|
|
}
|
|
return authorization
|
|
}
|
|
|
|
func resolveClientIP(c *gin.Context) string {
|
|
if forwarded := strings.TrimSpace(c.GetHeader("X-Forwarded-For")); forwarded != "" {
|
|
parts := strings.Split(forwarded, ",")
|
|
if len(parts) > 0 {
|
|
return strings.TrimSpace(parts[0])
|
|
}
|
|
}
|
|
return strings.TrimSpace(c.ClientIP())
|
|
}
|