diff --git a/code/allapp/allapp-go/.idea/data_source_mapping.xml b/code/allapp/allapp-go/.idea/data_source_mapping.xml index 09e8f97a..2d0befc2 100644 --- a/code/allapp/allapp-go/.idea/data_source_mapping.xml +++ b/code/allapp/allapp-go/.idea/data_source_mapping.xml @@ -1,7 +1,6 @@ - - + \ No newline at end of file diff --git a/code/allapp/allapp-go/.idea/db-forest-config.xml b/code/allapp/allapp-go/.idea/db-forest-config.xml new file mode 100644 index 00000000..a578503c --- /dev/null +++ b/code/allapp/allapp-go/.idea/db-forest-config.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/code/allapp/allapp-go/.idea/sqldialects.xml b/code/allapp/allapp-go/.idea/sqldialects.xml index 6df4889b..3f3b4305 100644 --- a/code/allapp/allapp-go/.idea/sqldialects.xml +++ b/code/allapp/allapp-go/.idea/sqldialects.xml @@ -1,6 +1,11 @@ + + + + + \ No newline at end of file diff --git a/code/allapp/allapp-go/api/handler/api.go b/code/allapp/allapp-go/api/handler/api.go index bec6efe2..5ed76414 100644 --- a/code/allapp/allapp-go/api/handler/api.go +++ b/code/allapp/allapp-go/api/handler/api.go @@ -1,12 +1,10 @@ package handler import ( - "allapp/utils/jwtx" - "github.com/gofiber/fiber/v3" ) // Hello handle api status func Hello(c fiber.Ctx) error { - return c.JSON(fiber.Map{"status": "success", "message": "Hello i'm ok!", "data": nil}) + panic("测试 panic") } diff --git a/code/allapp/allapp-go/api/handler/auth/index.go b/code/allapp/allapp-go/api/handler/auth/index.go new file mode 100644 index 00000000..8e054841 --- /dev/null +++ b/code/allapp/allapp-go/api/handler/auth/index.go @@ -0,0 +1,231 @@ +package auth + +import ( + "allapp/api/types" + "allapp/config" + "allapp/db" + "allapp/db/repo" + "allapp/utils" + "allapp/utils/errorx" + "allapp/utils/httpx" + "allapp/utils/jwtx" + "allapp/utils/requestx" + "allapp/utils/responsex" + "allapp/utils/uniqueid" + "errors" + "fmt" + + "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/client" +) + +// LoginQq qq登录 +func LoginQq(c fiber.Ctx) error { + dto := new(types.LoginQqDTO) + vo := new(types.LoginVO) + + if err := requestx.BindAndValidate(c, dto); err != nil { + return err + } + + return handleThirdLogin( + c, + dto.Openid, + dto.Nickname, + dto.Avatar, + 1, // QQ + vo, + ) +} + +func LoginWechat(c fiber.Ctx) error { + dto := new(types.LoginWeixinDTO) + vo := new(types.LoginVO) + + if err := requestx.BindAndValidate(c, dto); err != nil { + return err + } + + openid, accessToken, err := getWechatAccess(dto.Code) + if err != nil { + return responsex.Error(c, "微信登录失败,请重试") + } + + // 查是否已存在用户 + _, err = db.Queries.FindUserByOpenID(c.Context(), repo.FindUserByOpenIDParams{ + Openid: openid, + Type: 0, + }) + + if err == nil { + return handleThirdLogin(c, openid, "", "", 0, vo) + } + + if !errorx.IsNotFound(err) { + return err + } + + // 新用户 → 拉用户信息 + nickname, avatar, err := getWechatUserInfo(accessToken, openid) + if err != nil { + return responsex.Error(c, "微信登录失败,请重试") + } + + return handleThirdLogin(c, openid, nickname, avatar, 0, vo) +} + +func getWechatAccess(code string) (openid string, accessToken string, err error) { + bodyData, bodyCode, err := httpx.Get( + "https://api.weixin.qq.com/sns/oauth2/access_token", + client.Config{ + Param: map[string]string{ + "appid": config.GetConf().Wechat.AppId, + "secret": config.GetConf().Wechat.AppSecret, + "code": code, + "grant_type": "authorization_code", + }, + }, + ) + + if err != nil { + return "", "", err + } + + if bodyCode != 200 { + return "", "", fmt.Errorf("微信Http请求失败: %d", bodyCode) + } + + accessMap, err := utils.JSONStringToMap(bodyData) + if err != nil { + return "", "", err + } + + accessToken, _ = accessMap["access_token"].(string) + openid, _ = accessMap["openid"].(string) + + if accessToken == "" || openid == "" { + return "", "", errors.New("获取微信登录凭证失败") + } + + return +} + +func getWechatUserInfo(accessToken, openid string) (nickname, avatar string, err error) { + bodyData, bodyCode, err := httpx.Get( + "https://api.weixin.qq.com/sns/userinfo", + client.Config{ + Param: map[string]string{ + "access_token": accessToken, + "openid": openid, + }, + }, + ) + + if err != nil { + return "", "", err + } + + if bodyCode != 200 { + return "", "", fmt.Errorf("微信Http请求失败") + } + + userMap, err := utils.JSONStringToMap(bodyData) + if err != nil { + return "", "", err + } + + nickname, _ = userMap["nickname"].(string) + avatar, _ = userMap["headimgurl"].(string) + + return +} + +func handleThirdLogin( + c fiber.Ctx, + openid string, + nickname string, + avatar string, + loginType int32, // 0=微信 1=QQ + vo *types.LoginVO, +) error { + user, err := db.Queries.FindUserByOpenID(c.Context(), repo.FindUserByOpenIDParams{ + Openid: openid, + Type: loginType, + }) + + if err != nil { + if errorx.IsNotFound(err) { + // 用户不存在 → 注册 + return registerUser(c, openid, nickname, avatar, loginType, vo) + } + return err + } + + // 用户存在 + if user.Status == 0 { + return responsex.Error(c, "账号已被禁用") + } + + _ = db.Queries.UpdateUserLastLoginTime(c.Context(), user.UserID) + + token, err := jwtx.CreateToken(c, user.UserID) + if err != nil { + return err + } + + vo.Token = token + vo.UserId = user.UserID + vo.Nickname = user.Nickname + vo.Avatar = user.Avatar + + return responsex.OK(c, vo) +} + +// 注册用户 +func registerUser(c fiber.Ctx, openid, nickname, avatar string, loginType int32, vo *types.LoginVO) error { + userId := uniqueid.NextId() + + if nickname == "" { + nickname = fmt.Sprintf("用户_%d", userId) + } + if avatar == "" { + avatar = "https://default-avatar-url.com/default.png" + } + + err := db.WithTx(c.Context(), func(q *repo.Queries) error { + // 插入用户 + if err := q.InsertUser(c.Context(), repo.InsertUserParams{ + ID: userId, + Nickname: nickname, + Avatar: avatar, + Status: 1, + }); err != nil { + return err + } + + // 插入第三方登录信息 + if err := q.InsertUserOAuth(c.Context(), repo.InsertUserOAuthParams{ + ID: uniqueid.NextId(), + UserID: userId, + Type: loginType, + Openid: openid, + }); err != nil { + return err + } + + return nil + }) + + if err != nil { + return err + } + + token, _ := jwtx.CreateToken(c, userId) + + vo.Token = token + vo.UserId = userId + vo.Nickname = nickname + vo.Avatar = avatar + + return responsex.OK(c, vo) +} diff --git a/code/allapp/allapp-go/api/router/middleware/auth.go b/code/allapp/allapp-go/api/router/middleware/auth.go new file mode 100644 index 00000000..770e563f --- /dev/null +++ b/code/allapp/allapp-go/api/router/middleware/auth.go @@ -0,0 +1,47 @@ +package middleware + +import ( + "allapp/utils/jwtx" + "allapp/utils/responsex" + "strings" + + "github.com/gofiber/fiber/v3" +) + +const CtxUserIDKey = "user_id" + +// Auth 登录校验中间件 +func Auth() fiber.Handler { + return func(c fiber.Ctx) error { + + token := strings.TrimSpace(c.Get("Token")) + if token == "" { + return responsex.Unauthorized(c, "未登录") + } + + verifyToken, ok := jwtx.VerifyToken(c.Context(), token) + if !ok { + return responsex.Unauthorized(c, "登录已过期") + } + + c.Locals(CtxUserIDKey, verifyToken.UserID) + + return c.Next() + } +} + +func GetUserID(c fiber.Ctx) (int64, error) { + v := c.Locals(CtxUserIDKey) + + if v == nil { + return 0, responsex.Unauthorized(c, "登录已过期") + } + + userID, ok := v.(int64) + + if !ok { + return 0, responsex.Unauthorized(c, "登录已过期") + } + + return userID, nil +} diff --git a/code/allapp/allapp-go/api/middleware/logger.go b/code/allapp/allapp-go/api/router/middleware/logger.go similarity index 90% rename from code/allapp/allapp-go/api/middleware/logger.go rename to code/allapp/allapp-go/api/router/middleware/logger.go index 29547e63..e0b4a4cb 100644 --- a/code/allapp/allapp-go/api/middleware/logger.go +++ b/code/allapp/allapp-go/api/router/middleware/logger.go @@ -20,7 +20,7 @@ func Logger() fiber.Handler { duration := time.Since(start) // 记录日志 - log.WithContext(c.Context()).Infow("API Request", + log.Infow("API Request", "method", c.Method(), "path", c.Path(), "status", c.Response().StatusCode(), diff --git a/code/allapp/allapp-go/api/router/middleware/space_guard.go b/code/allapp/allapp-go/api/router/middleware/space_guard.go new file mode 100644 index 00000000..fbf229e9 --- /dev/null +++ b/code/allapp/allapp-go/api/router/middleware/space_guard.go @@ -0,0 +1,62 @@ +package middleware + +import ( + "allapp/db" + "allapp/db/repo" + "allapp/utils/errorx" + "allapp/utils/redisx" + "allapp/utils/responsex" + "strconv" + "strings" + + "github.com/gofiber/fiber/v3" +) + +const CtxSpaceIDKey = "space_id" + +func SpaceGuard() fiber.Handler { + return func(c fiber.Ctx) error { + userID, err := GetUserID(c) + + if err != nil { + return err + } + + spaceIDStr := strings.TrimSpace(c.Get("SPACE_ID")) + + spaceID, err := strconv.ParseInt(spaceIDStr, 10, 64) + if err != nil || spaceID <= 0 { + return responsex.SpaceError(c, "请选择空间") + } + + // 校验 + inSpace, err := redisx.SpaceIsMember(spaceID, userID) + + if inSpace { + return c.Next() + } + + // 检验空间是否存在 + space, err := db.Queries.GetSpaceById(c.Context(), spaceID) + + if err != nil { + if errorx.IsNotFound(err) { + // 未找到 + return responsex.SpaceError(c, "空间已失效") + } + return err + } + + // 空间有效,判断是否在该空间内 + role, err := db.Queries.GetUserSpaceRole(c.Context(), repo.GetUserSpaceRoleParams{ + SpaceID: spaceID, + UserID: spaceID, + }) + if err != nil { + if errorx.IsNotFound(err) { + + } + } + + } +} diff --git a/code/allapp/allapp-go/api/router/router.go b/code/allapp/allapp-go/api/router/router.go index 673adfbb..9f098803 100644 --- a/code/allapp/allapp-go/api/router/router.go +++ b/code/allapp/allapp-go/api/router/router.go @@ -1,7 +1,7 @@ package router import ( - "allapp/api/handler" + "allapp/api/handler/auth" "allapp/config" "github.com/gofiber/fiber/v3" @@ -10,5 +10,13 @@ import ( func SetupRouters(app *fiber.App) { api := app.Group(config.GetConf().Server.BaseUrl) - api.Get("/", handler.Hello) + public := api.Group("") + //private := api.Group("", middleware.Auth()) + + // auth + authRouter := public.Group("/auth") + authRouter.Post("/login/qq", auth.LoginQq) + authRouter.Post("/login/wechat", auth.LoginWechat) + + // 其他的都带中间件 } diff --git a/code/allapp/allapp-go/api/types/auth.go b/code/allapp/allapp-go/api/types/auth.go new file mode 100644 index 00000000..5854f421 --- /dev/null +++ b/code/allapp/allapp-go/api/types/auth.go @@ -0,0 +1,18 @@ +package types + +type LoginQqDTO struct { + Openid string `json:"openid" validate:"required"` + Nickname string `json:"nickname"` + Avatar string `json:"avatar"` +} + +type LoginWeixinDTO struct { + Code string `json:"code" validate:"required"` +} + +type LoginVO struct { + Token string `json:"token"` + UserId int64 `json:"userId"` + Nickname string `json:"nickname"` + Avatar string `json:"avatar"` +} diff --git a/code/allapp/allapp-go/cmd/main.go b/code/allapp/allapp-go/cmd/main.go index 0de5fb63..e89e72c7 100644 --- a/code/allapp/allapp-go/cmd/main.go +++ b/code/allapp/allapp-go/cmd/main.go @@ -1,28 +1,61 @@ package main import ( - "allapp/api/middleware" "allapp/api/router" + "allapp/api/router/middleware" "allapp/config" + "allapp/utils/responsex" + "fmt" + "runtime/debug" + "github.com/go-playground/validator/v10" "github.com/gofiber/fiber/v3" "github.com/gofiber/fiber/v3/log" - recoverer "github.com/gofiber/fiber/v3/middleware/recover" + recover2 "github.com/gofiber/fiber/v3/middleware/recover" "github.com/gofiber/fiber/v3/middleware/requestid" "go.uber.org/zap" ) -//func errorHandler(ctx fiber.Ctx, err error) error { -// -//} +type structValidator struct { + validate *validator.Validate +} + +// Validate Validator needs to implement the Validate method +func (v *structValidator) Validate(out any) error { + return v.validate.Struct(out) +} func main() { if err := config.InitConfig(); err != nil { panic(err) } - app := fiber.New() - app.Use(recoverer.New(), requestid.New(), middleware.Logger()) + app := fiber.New(fiber.Config{ + StructValidator: &structValidator{validate: validator.New()}, + ErrorHandler: func(ctx fiber.Ctx, err error) error { + log.WithContext(ctx.Context()).Errorw("系统异常", + "method", ctx.Method(), + "path", ctx.Path(), + "status", ctx.Response().StatusCode(), + "error", err, + ) + + return responsex.SystemError(ctx, fmt.Sprintf("系统异常 - %v", err)) + }, + }) + + app.Use(recover2.New(recover2.Config{ + EnableStackTrace: true, + StackTraceHandler: func(ctx fiber.Ctx, err any) { + stack := debug.Stack() // 获取 panic 堆栈 + + // 打日志到 zap + log.WithContext(ctx.Context()).Errorw("系统堆栈异常", + "error", err, + "stack", string(stack), + ) + }, + }), requestid.New(), middleware.Logger()) router.SetupRouters(app) diff --git a/code/allapp/allapp-go/config/database.go b/code/allapp/allapp-go/config/database.go new file mode 100644 index 00000000..eefb6e9c --- /dev/null +++ b/code/allapp/allapp-go/config/database.go @@ -0,0 +1,50 @@ +package config + +import ( + "allapp/db/repo" + "context" + "fmt" + "time" + + "github.com/jackc/pgx/v5/pgxpool" +) + +func initDB() (*pgxpool.Pool, *repo.Queries, error) { + cfg := conf.Postgres + + sslMode := "disable" + if cfg.SslMode { + sslMode = "require" + } + + dsn := fmt.Sprintf( + "postgres://%s:%s@%s:%d/%s?sslmode=%s&TimeZone=%s", + cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Dbname, sslMode, cfg.TimeZone, + ) + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // 使用可修改配置 + cfgPool, err := pgxpool.ParseConfig(dsn) + if err != nil { + return nil, nil, fmt.Errorf("parse pgx config failed: %w", err) + } + + cfgPool.MaxConns = cfg.MaxOpenConns + cfgPool.MinConns = cfg.MaxIdleConns + cfgPool.MaxConnLifetime = cfg.ConnMaxLifetime + + pool, err := pgxpool.NewWithConfig(ctx, cfgPool) + if err != nil { + return nil, nil, fmt.Errorf("create pgx pool failed: %w", err) + } + + // 测试连接 + if err := pool.Ping(ctx); err != nil { + return nil, nil, fmt.Errorf("ping database failed: %w", err) + } + + queries := repo.New(pool) + return pool, queries, nil +} diff --git a/code/allapp/allapp-go/config/index.go b/code/allapp/allapp-go/config/index.go index aa08ee5e..7cbbacca 100644 --- a/code/allapp/allapp-go/config/index.go +++ b/code/allapp/allapp-go/config/index.go @@ -1,6 +1,8 @@ package config import ( + "allapp/db" + "allapp/utils/redisx" "fmt" "os" "path/filepath" @@ -25,6 +27,22 @@ func InitConfig() error { initLogger() initUniqueId() + // 加载数据库 + pool, queries, err := initDB() + if err != nil { + return fmt.Errorf("加载数据库失败: %w", err) + } + + db.Pool = pool + db.Queries = queries + + // 加载 redis + redis, err := initRedis() + if err != nil { + return fmt.Errorf("加载Redis失败: %w", err) + } + redisx.Client = redis + return nil } @@ -59,6 +77,9 @@ func defaultConfig() *Config { MaxAge: 30, Compress: true, }, + Redis: RedisConfig{ + Port: 6379, + }, } } diff --git a/code/allapp/allapp-go/config/logger.go b/code/allapp/allapp-go/config/logger.go index 189c0a5d..3605cdc2 100644 --- a/code/allapp/allapp-go/config/logger.go +++ b/code/allapp/allapp-go/config/logger.go @@ -27,7 +27,7 @@ func initLogger() { ExtraKeys: []string{"request_id"}, ZapOptions: []zap.Option{ zap.AddCaller(), // 打开 caller - zap.AddCallerSkip(2), // 跳过一层 Fiber 调用 + zap.AddCallerSkip(2), // 跳过 2 层 Fiber 调用 }, CoreConfigs: []fiberZap.CoreConfig{ { diff --git a/code/allapp/allapp-go/config/redis.go b/code/allapp/allapp-go/config/redis.go new file mode 100644 index 00000000..e4a264ae --- /dev/null +++ b/code/allapp/allapp-go/config/redis.go @@ -0,0 +1,29 @@ +package config + +import ( + "context" + "fmt" + "time" + + "github.com/redis/go-redis/v9" +) + +func initRedis() (*redis.Client, error) { + cfg := GetConf().Redis + + rdb := redis.NewClient(&redis.Options{ + Addr: fmt.Sprintf("%s:%d", cfg.Host, cfg.Port), + Password: cfg.Password, + DB: cfg.Db, + }) + + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + + if err := rdb.Ping(ctx).Err(); err != nil { + _ = rdb.Close() + return nil, fmt.Errorf("redis ping failed: %w", err) + } + + return rdb, nil +} diff --git a/code/allapp/allapp-go/config/types.go b/code/allapp/allapp-go/config/types.go index b2792b1a..8bdb079d 100644 --- a/code/allapp/allapp-go/config/types.go +++ b/code/allapp/allapp-go/config/types.go @@ -11,6 +11,7 @@ type Config struct { Postgres PostgresConfig `mapstructure:"postgres"` Log LogConfig `mapstructure:"log"` Wechat WechatConfig `mapstructure:"wechat"` + Redis RedisConfig `mapstructure:"redis"` } type ServerConfig struct { @@ -55,3 +56,10 @@ type WechatConfig struct { AppId string `mapstructure:"app_id"` AppSecret string `mapstructure:"app_secret"` } + +type RedisConfig struct { + Host string `mapstructure:"host"` + Port int `mapstructure:"port"` + Db int `mapstructure:"db"` + Password string `mapstructure:"password"` +} diff --git a/code/allapp/allapp-go/db/index.go b/code/allapp/allapp-go/db/index.go new file mode 100644 index 00000000..489246a8 --- /dev/null +++ b/code/allapp/allapp-go/db/index.go @@ -0,0 +1,70 @@ +package db + +import ( + "allapp/db/repo" + "context" + "fmt" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" +) + +var ( + Pool *pgxpool.Pool + Queries *repo.Queries +) + +type SQLCBatch interface { + Exec(func(int, error)) +} + +// WithTx 执行事务,支持 panic 和 error 自动回滚 +// 默认使用全局 DB,调用更简洁 +func WithTx(ctx context.Context, fn func(q *repo.Queries) error) (err error) { + return WithTxPool(ctx, Pool, fn) +} + +// WithTxPool 支持自定义连接池 +func WithTxPool(ctx context.Context, pool *pgxpool.Pool, fn func(q *repo.Queries) error) (err error) { + tx, err := pool.BeginTx(ctx, pgx.TxOptions{}) + if err != nil { + return err + } + + defer func() { + if p := recover(); p != nil { + // panic 时回滚事务 + if rbErr := tx.Rollback(ctx); rbErr != nil { + fmt.Printf("rollback failed during panic: %v\n", rbErr) + } + panic(p) + } else if err != nil { + // 回滚事务,并捕获 rollback 错误 + if rbErr := tx.Rollback(ctx); rbErr != nil { + err = fmt.Errorf("rollback failed: %v, original error: %w", rbErr, err) + } + } else { + // 提交事务,并捕获 commit 错误 + if commitErr := tx.Commit(ctx); commitErr != nil { + err = fmt.Errorf("commit failed: %w", commitErr) + } + } + }() + + q := Queries.WithTx(tx) + err = fn(q) + return err +} + +// RunBatch 通用批处理执行器(适配所有 sqlc Batch) +func RunBatch(ctx context.Context, batch SQLCBatch) error { + var firstErr error + + batch.Exec(func(i int, err error) { + if err != nil && firstErr == nil { + firstErr = err + } + }) + + return firstErr +} diff --git a/code/allapp/allapp-go/db/queries/space.sql b/code/allapp/allapp-go/db/queries/space.sql new file mode 100644 index 00000000..fee88a1d --- /dev/null +++ b/code/allapp/allapp-go/db/queries/space.sql @@ -0,0 +1,4 @@ + +-- 根据id获取分享空间信息 +-- name: GetSpaceById :one +SELECT * FROM space WHERE id = $1; diff --git a/code/allapp/allapp-go/db/queries/space_member.sql b/code/allapp/allapp-go/db/queries/space_member.sql new file mode 100644 index 00000000..70717da4 --- /dev/null +++ b/code/allapp/allapp-go/db/queries/space_member.sql @@ -0,0 +1,6 @@ +-- 获取用户在指定空间的角色 +-- name: GetUserSpaceRole :one +SELECT role +FROM space_member +WHERE user_id = $1 + AND space_id = $2; \ No newline at end of file diff --git a/code/allapp/allapp-go/db/queries/user.sql b/code/allapp/allapp-go/db/queries/user.sql new file mode 100644 index 00000000..4ff21180 --- /dev/null +++ b/code/allapp/allapp-go/db/queries/user.sql @@ -0,0 +1,31 @@ +-- name: FindUserByOpenID :one +SELECT + u.id AS user_id, + u.nickname, + u.avatar, + u.status, + o.type AS login_type, + o.openid +FROM user_oauth o + JOIN "user" u ON u.id = o.user_id +WHERE o.openid = $1 + AND o.type = $2 +LIMIT 1; + +-- name: InsertUser :exec +INSERT INTO "user" ( + id, + nickname, + avatar, + status, + create_time, + update_time, + last_login_time +) VALUES ( + $1, $2, $3,$4, NOW(), NOW(),now() + ); + +-- name: UpdateUserLastLoginTime :exec +UPDATE "user" +SET last_login_time = NOW() +WHERE id = $1; diff --git a/code/allapp/allapp-go/db/queries/user_oauth.sql b/code/allapp/allapp-go/db/queries/user_oauth.sql new file mode 100644 index 00000000..2fbac40f --- /dev/null +++ b/code/allapp/allapp-go/db/queries/user_oauth.sql @@ -0,0 +1,12 @@ +-- name: InsertUserOAuth :exec +INSERT INTO user_oauth ( + id, + user_id, + type, + openid, + create_time, + update_time +) VALUES ( + $1, $2, $3, $4, NOW(), NOW() +); + diff --git a/code/allapp/allapp-go/db/repo/db.go b/code/allapp/allapp-go/db/repo/db.go new file mode 100644 index 00000000..71f6cab5 --- /dev/null +++ b/code/allapp/allapp-go/db/repo/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 + +package repo + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) + Query(context.Context, string, ...interface{}) (pgx.Rows, error) + QueryRow(context.Context, string, ...interface{}) pgx.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx pgx.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/code/allapp/allapp-go/db/repo/models.go b/code/allapp/allapp-go/db/repo/models.go new file mode 100644 index 00000000..641af819 --- /dev/null +++ b/code/allapp/allapp-go/db/repo/models.go @@ -0,0 +1,46 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 + +package repo + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Space struct { + ID int64 + Name string + InviteCode string + OwnerID int64 + CreateTime pgtype.Timestamptz + UpdateTime pgtype.Timestamptz +} + +type SpaceMember struct { + ID int64 + SpaceID int64 + UserID int64 + Role int16 + JoinTime pgtype.Timestamptz + UpdateTime pgtype.Timestamptz +} + +type User struct { + ID int64 + Nickname string + Avatar string + Status int32 + LastLoginTime pgtype.Timestamptz + CreateTime pgtype.Timestamptz + UpdateTime pgtype.Timestamptz +} + +type UserOauth struct { + ID int64 + UserID int64 + Type int32 + Openid string + CreateTime pgtype.Timestamptz + UpdateTime pgtype.Timestamptz +} diff --git a/code/allapp/allapp-go/db/repo/space.sql.go b/code/allapp/allapp-go/db/repo/space.sql.go new file mode 100644 index 00000000..4653fe37 --- /dev/null +++ b/code/allapp/allapp-go/db/repo/space.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 +// source: space.sql + +package repo + +import ( + "context" +) + +const getSpaceById = `-- name: GetSpaceById :one +SELECT id, name, invite_code, owner_id, create_time, update_time FROM space WHERE id = $1 +` + +// 根据id获取分享空间信息 +func (q *Queries) GetSpaceById(ctx context.Context, id int64) (Space, error) { + row := q.db.QueryRow(ctx, getSpaceById, id) + var i Space + err := row.Scan( + &i.ID, + &i.Name, + &i.InviteCode, + &i.OwnerID, + &i.CreateTime, + &i.UpdateTime, + ) + return i, err +} diff --git a/code/allapp/allapp-go/db/repo/space_member.sql.go b/code/allapp/allapp-go/db/repo/space_member.sql.go new file mode 100644 index 00000000..0166b80e --- /dev/null +++ b/code/allapp/allapp-go/db/repo/space_member.sql.go @@ -0,0 +1,30 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 +// source: space_member.sql + +package repo + +import ( + "context" +) + +const getUserSpaceRole = `-- name: GetUserSpaceRole :one +SELECT role +FROM space_member +WHERE user_id = $1 + AND space_id = $2 +` + +type GetUserSpaceRoleParams struct { + UserID int64 + SpaceID int64 +} + +// 获取用户在指定空间的角色 +func (q *Queries) GetUserSpaceRole(ctx context.Context, arg GetUserSpaceRoleParams) (int16, error) { + row := q.db.QueryRow(ctx, getUserSpaceRole, arg.UserID, arg.SpaceID) + var role int16 + err := row.Scan(&role) + return role, err +} diff --git a/code/allapp/allapp-go/db/repo/user.sql.go b/code/allapp/allapp-go/db/repo/user.sql.go new file mode 100644 index 00000000..b7fd8170 --- /dev/null +++ b/code/allapp/allapp-go/db/repo/user.sql.go @@ -0,0 +1,95 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 +// source: user.sql + +package repo + +import ( + "context" +) + +const findUserByOpenID = `-- name: FindUserByOpenID :one +SELECT + u.id AS user_id, + u.nickname, + u.avatar, + u.status, + o.type AS login_type, + o.openid +FROM user_oauth o + JOIN "user" u ON u.id = o.user_id +WHERE o.openid = $1 + AND o.type = $2 +LIMIT 1 +` + +type FindUserByOpenIDParams struct { + Openid string + Type int32 +} + +type FindUserByOpenIDRow struct { + UserID int64 + Nickname string + Avatar string + Status int32 + LoginType int32 + Openid string +} + +func (q *Queries) FindUserByOpenID(ctx context.Context, arg FindUserByOpenIDParams) (FindUserByOpenIDRow, error) { + row := q.db.QueryRow(ctx, findUserByOpenID, arg.Openid, arg.Type) + var i FindUserByOpenIDRow + err := row.Scan( + &i.UserID, + &i.Nickname, + &i.Avatar, + &i.Status, + &i.LoginType, + &i.Openid, + ) + return i, err +} + +const insertUser = `-- name: InsertUser :exec +INSERT INTO "user" ( + id, + nickname, + avatar, + status, + create_time, + update_time, + last_login_time +) VALUES ( + $1, $2, $3,$4, NOW(), NOW(),now() + ) +` + +type InsertUserParams struct { + ID int64 + Nickname string + Avatar string + Status int32 +} + +func (q *Queries) InsertUser(ctx context.Context, arg InsertUserParams) error { + _, err := q.db.Exec(ctx, insertUser, + arg.ID, + arg.Nickname, + arg.Avatar, + arg.Status, + ) + return err +} + +const updateUserLastLoginTime = `-- name: UpdateUserLastLoginTime :exec +UPDATE "user" +SET last_login_time = NOW() +WHERE id = $1 +` + +func (q *Queries) UpdateUserLastLoginTime(ctx context.Context, id int64) error { + _, err := q.db.Exec(ctx, updateUserLastLoginTime, id) + return err +} diff --git a/code/allapp/allapp-go/db/repo/user_oauth.sql.go b/code/allapp/allapp-go/db/repo/user_oauth.sql.go new file mode 100644 index 00000000..771e0a74 --- /dev/null +++ b/code/allapp/allapp-go/db/repo/user_oauth.sql.go @@ -0,0 +1,40 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 +// source: user_oauth.sql + +package repo + +import ( + "context" +) + +const insertUserOAuth = `-- name: InsertUserOAuth :exec +INSERT INTO user_oauth ( + id, + user_id, + type, + openid, + create_time, + update_time +) VALUES ( + $1, $2, $3, $4, NOW(), NOW() +) +` + +type InsertUserOAuthParams struct { + ID int64 + UserID int64 + Type int32 + Openid string +} + +func (q *Queries) InsertUserOAuth(ctx context.Context, arg InsertUserOAuthParams) error { + _, err := q.db.Exec(ctx, insertUserOAuth, + arg.ID, + arg.UserID, + arg.Type, + arg.Openid, + ) + return err +} diff --git a/code/allapp/allapp-go/db/schema.sql b/code/allapp/allapp-go/db/schema.sql new file mode 100644 index 00000000..433a0fbf --- /dev/null +++ b/code/allapp/allapp-go/db/schema.sql @@ -0,0 +1,44 @@ +create table "user" +( + id bigint not null + primary key, + nickname varchar(255) not null, + avatar varchar(255) not null, + status int default 0 not null, + last_login_time timestamp with time zone, + create_time timestamp with time zone default now(), + update_time timestamp with time zone default now() +); + +create table user_oauth +( + id bigint not null +primary key, + user_id bigint not null, + type int default 0 not null, + openid varchar(255) not null, + create_time timestamp with time zone default now(), + update_time timestamp with time zone default now() +); + +create table space +( + id bigint not null + primary key, + name varchar(255) not null, + invite_code varchar(30) not null, + owner_id bigint not null, + create_time timestamp with time zone default now(), + update_time timestamp with time zone default now() +); + +create table space_member +( + id bigint not null + primary key, + space_id bigint not null, + user_id bigint not null, + role smallint default 2 not null, + join_time timestamp with time zone default now(), + update_time timestamp with time zone default now() +); diff --git a/code/allapp/allapp-go/go.mod b/code/allapp/allapp-go/go.mod index d1cbb50e..906cdf48 100644 --- a/code/allapp/allapp-go/go.mod +++ b/code/allapp/allapp-go/go.mod @@ -14,17 +14,31 @@ require ( require ( github.com/MicahParks/keyfunc/v2 v2.1.0 // indirect github.com/andybalholm/brotli v1.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.12 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.30.1 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/gofiber/schema v1.7.0 // indirect github.com/gofiber/utils/v2 v2.0.2 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.8.0 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/klauspost/compress v1.18.4 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/philhofer/fwd v1.2.0 // indirect + github.com/redis/go-redis/v9 v9.18.0 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect + github.com/shopspring/decimal v1.4.0 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect @@ -33,10 +47,13 @@ require ( github.com/tinylib/msgp v1.6.3 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.69.0 // indirect + github.com/x448/float16 v0.8.4 // indirect + go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.48.0 // indirect - golang.org/x/net v0.50.0 // indirect + golang.org/x/net v0.51.0 // indirect + golang.org/x/sync v0.19.0 // indirect golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.34.0 // indirect ) diff --git a/code/allapp/allapp-go/go.sum b/code/allapp/allapp-go/go.sum index 1ec2f219..6a22f891 100644 --- a/code/allapp/allapp-go/go.sum +++ b/code/allapp/allapp-go/go.sum @@ -2,8 +2,25 @@ github.com/MicahParks/keyfunc/v2 v2.1.0 h1:6ZXKb9Rp6qp1bDbJefnG7cTH8yMN1IC/4nf+G github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4OeE/yHVMteCkw9k= github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= +github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w= +github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= @@ -22,8 +39,18 @@ github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63Y github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo= +github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= @@ -32,10 +59,17 @@ github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0 github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/redis/go-redis/v9 v9.18.0 h1:pMkxYPkEbMPwRdenAzUNyFNrDgHx9U+DrBabWNfSRQs= +github.com/redis/go-redis/v9 v9.18.0/go.mod h1:k3ufPphLU5YXwNTUcCRXGxUoF1fqxnhFQmscfkCoDA0= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4= github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= @@ -46,6 +80,11 @@ github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tinylib/msgp v1.6.3 h1:bCSxiTz386UTgyT1i0MSCvdbWjVW+8sG3PjkGsZQt4s= @@ -54,6 +93,10 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.69.0 h1:fNLLESD2SooWeh2cidsuFtOcrEi4uB4m1mPrkJMZyVI= github.com/valyala/fasthttp v1.69.0/go.mod h1:4wA4PfAraPlAsJ5jMSqCE2ug5tqUPwKXxVj8oNECGcw= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= @@ -64,6 +107,10 @@ golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= +golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= +golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= @@ -72,3 +119,6 @@ golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/code/allapp/allapp-go/resources/application-dev.yaml b/code/allapp/allapp-go/resources/application-dev.yaml index e69de29b..1c3c7b94 100644 --- a/code/allapp/allapp-go/resources/application-dev.yaml +++ b/code/allapp/allapp-go/resources/application-dev.yaml @@ -0,0 +1,17 @@ +postgres: + host: 117.72.182.135 + port: 5432 + user: postgres + password: zhang520.. + dbname: app + timezone: Asia/Shanghai + max_open_conns: 10 + max_idle_conns: 5 + conn_max_lifetime: 30m + sll_mode: false + +redis: + host: 117.72.182.135 + port: 6379 + password: zhang520.. + db: 0 \ No newline at end of file diff --git a/code/allapp/allapp-go/sqlc.yaml b/code/allapp/allapp-go/sqlc.yaml new file mode 100644 index 00000000..8a6304f7 --- /dev/null +++ b/code/allapp/allapp-go/sqlc.yaml @@ -0,0 +1,10 @@ +version: "2" +sql: + - engine: "postgresql" # 数据库 + queries: "db/queries" # query.sql文件的路径,该文件主要用于存储DML + schema: "db/schema.sql" # schema.sql文件的路径,该文件主要用于存储DDL + gen: + go: + package: "repo" # 模块的包名 + out: "db/repo" # 代码生成路径 + sql_package: "pgx/v5" diff --git a/code/allapp/allapp-go/utils/errorx/errorx.go b/code/allapp/allapp-go/utils/errorx/errorx.go new file mode 100644 index 00000000..c5a2efd0 --- /dev/null +++ b/code/allapp/allapp-go/utils/errorx/errorx.go @@ -0,0 +1,13 @@ +package errorx + +import ( + "database/sql" + "errors" + + "github.com/jackc/pgx/v5" +) + +// IsNotFound 判断 err 是否因为数据库中没找到数据 +func IsNotFound(err error) bool { + return errors.Is(err, sql.ErrNoRows) || errors.Is(err, pgx.ErrNoRows) +} diff --git a/code/allapp/allapp-go/utils/httpx/index.go b/code/allapp/allapp-go/utils/httpx/index.go new file mode 100644 index 00000000..b34addd7 --- /dev/null +++ b/code/allapp/allapp-go/utils/httpx/index.go @@ -0,0 +1,99 @@ +package httpx + +import ( + "context" + "time" + + "github.com/gofiber/fiber/v3/client" +) + +// 全局 Fiber Client +var cc = client.New() + +func init() { + cc.SetTimeout(10 * time.Second) +} + +// mergeConfig 合并默认配置和用户配置 +func mergeConfig(defaultCfg, userCfg client.Config) client.Config { + if userCfg.Ctx != nil { + defaultCfg.Ctx = userCfg.Ctx + } + if userCfg.Body != nil { + defaultCfg.Body = userCfg.Body + } + if userCfg.Header != nil { + if defaultCfg.Header == nil { + defaultCfg.Header = map[string]string{} + } + for k, v := range userCfg.Header { + defaultCfg.Header[k] = v + } + } + if userCfg.Param != nil { + defaultCfg.Param = userCfg.Param + } + if userCfg.PathParam != nil { + defaultCfg.PathParam = userCfg.PathParam + } + if userCfg.FormData != nil { + defaultCfg.FormData = userCfg.FormData + } + if userCfg.Timeout != 0 { + defaultCfg.Timeout = userCfg.Timeout + } + if userCfg.UserAgent != "" { + defaultCfg.UserAgent = userCfg.UserAgent + } + if userCfg.Referer != "" { + defaultCfg.Referer = userCfg.Referer + } + defaultCfg.DisablePathNormalizing = userCfg.DisablePathNormalizing + defaultCfg.MaxRedirects = userCfg.MaxRedirects + + return defaultCfg +} + +func Get(url string, cfg client.Config) (string, int, error) { + defaultCfg := client.Config{ + Ctx: context.Background(), + } + finalCfg := mergeConfig(defaultCfg, cfg) + + resp, err := cc.Get(url, finalCfg) + if err != nil { + return "", 0, err + } + + return string(resp.Body()), resp.StatusCode(), nil +} + +func PostJSON(url string, data any, cfg client.Config) (string, int, error) { + defaultCfg := client.Config{ + Ctx: context.Background(), + Body: data, + Header: map[string]string{"Content-Type": "application/json"}, + } + finalCfg := mergeConfig(defaultCfg, cfg) + + resp, err := cc.Post(url, finalCfg) + if err != nil { + return "", 0, err + } + return string(resp.Body()), resp.StatusCode(), nil +} + +func PostForm(url string, formData map[string]string, cfg client.Config) (string, int, error) { + defaultCfg := client.Config{ + Ctx: context.Background(), + FormData: formData, + Header: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, + } + finalCfg := mergeConfig(defaultCfg, cfg) + + resp, err := cc.Post(url, finalCfg) + if err != nil { + return "", 0, err + } + return string(resp.Body()), resp.StatusCode(), nil +} diff --git a/code/allapp/allapp-go/utils/index.go b/code/allapp/allapp-go/utils/index.go new file mode 100644 index 00000000..9a02a40e --- /dev/null +++ b/code/allapp/allapp-go/utils/index.go @@ -0,0 +1,20 @@ +package utils + +import "encoding/json" + +// JSONStringToStruct 将 JSON 字符串反序列化到指定结构体类型 +func JSONStringToStruct[T any](jsonStr string) (*T, error) { + var result T + if err := json.Unmarshal([]byte(jsonStr), &result); err != nil { + return nil, err + } + return &result, nil +} + +func JSONStringToMap(jsonStr string) (map[string]interface{}, error) { + var result map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &result); err != nil { + return nil, err + } + return result, nil +} diff --git a/code/allapp/allapp-go/utils/jwtx/index.go b/code/allapp/allapp-go/utils/jwtx/index.go index 54788e7e..9b8689d2 100644 --- a/code/allapp/allapp-go/utils/jwtx/index.go +++ b/code/allapp/allapp-go/utils/jwtx/index.go @@ -3,13 +3,13 @@ package jwtx import ( "allapp/config" "context" - "errors" "sync" "time" "github.com/golang-jwt/jwt/v5" ) +// CustomClaims 定义 JWT 自定义 Claims type CustomClaims struct { UserID int64 `json:"user_id"` jwt.RegisteredClaims @@ -26,8 +26,8 @@ var ( once sync.Once ) -// InitJwt 初始化 JWT 单例 -func InitJwt() { +// getManager 自动初始化单例 +func getManager() *jwtManager { once.Do(func() { cfg := config.GetConf().JWT manager = &jwtManager{ @@ -35,20 +35,19 @@ func InitJwt() { tokenExpiry: cfg.AccessExpiry, } }) + return manager } // CreateToken 生成 JWT func CreateToken(ctx context.Context, userID int64) (string, error) { - if manager == nil { - return "", errors.New("jwt manager not initialized") - } - return manager.createToken(userID) + m := getManager() + return m.createToken(userID) } // VerifyToken 校验 token 并返回 claims -func VerifyToken(ctx context.Context, tokenString string) (*CustomClaims, error) { +func VerifyToken(ctx context.Context, tokenString string) (*CustomClaims, bool) { if tokenString == "" || manager == nil { - return nil, errors.New("token empty or manager not initialized") + return nil, false } token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) { @@ -56,15 +55,15 @@ func VerifyToken(ctx context.Context, tokenString string) (*CustomClaims, error) }) if err != nil || !token.Valid { - return nil, errors.New("invalid token") + return nil, false } claims, ok := token.Claims.(*CustomClaims) if !ok { - return nil, errors.New("invalid claims") + return nil, false } - return claims, nil + return claims, true } // createToken 私有方法 diff --git a/code/allapp/allapp-go/utils/pgtypex/pgtypex.go b/code/allapp/allapp-go/utils/pgtypex/pgtypex.go new file mode 100644 index 00000000..012fd682 --- /dev/null +++ b/code/allapp/allapp-go/utils/pgtypex/pgtypex.go @@ -0,0 +1,161 @@ +package pgtypex + +import ( + "strings" + "time" + + "github.com/jackc/pgx/v5/pgtype" + "github.com/shopspring/decimal" +) + +func NumericToString(n pgtype.Numeric) string { + if n.Int == nil || n.NaN { + return "0.00" + } + + // 转成 decimal 保证精度 + dec := decimal.NewFromBigInt(n.Int, int32(n.Exp)) + return dec.StringFixed(2) // 保留两位小数 +} +func NumericToDecimal(n pgtype.Numeric) decimal.Decimal { + if n.Int == nil || n.NaN { + return decimal.Zero + } + return decimal.NewFromBigInt(n.Int, int32(n.Exp)) +} + +// TimestampToDateString 转为 "YYYY-MM-DD" +func TimestampToDateString(ts pgtype.Timestamp) string { + if ts.Time.IsZero() { + return "" + } + return ts.Time.Format("2006-01-02") +} + +// TimestampToDateTimeString 转为 "YYYY-MM-DD HH:MM:SS" +func TimestampToDateTimeString(ts pgtype.Timestamp) string { + if ts.Time.IsZero() { + return "" + } + return ts.Time.Format("2006-01-02 15:04:05") +} + +// StringToNumeric 将字符串金额转换为 pgtype.Numeric +func StringToNumeric(amountStr string) pgtype.Numeric { + if strings.TrimSpace(amountStr) == "" { + return pgtype.Numeric{Valid: false} + } + + dec, err := decimal.NewFromString(amountStr) + if err != nil { + return pgtype.Numeric{Valid: false} + } + + // 保留两位小数,四舍五入 + dec = dec.Round(2) + + // 乘以 100 转整数 + intVal := dec.Mul(decimal.NewFromInt(100)).BigInt() + + return pgtype.Numeric{ + Int: intVal, + Exp: -2, // 固定两位小数 + NaN: false, + Valid: true, + } +} + +// StringToText 将字符串转换为 pgtype.Text +// 空字符串返回零值 Text +func StringToText(s string) pgtype.Text { + if s == "" { + return pgtype.Text{Valid: false} + } + return pgtype.Text{ + String: s, + Valid: true, + } +} + +// StringToTimestamp 将字符串解析为 pgtype.Timestamp +// 支持格式:YYYY-MM-DD HH:MM:SS 或 YYYY-MM-DD +// 解析失败或空字符串返回零值 Timestamp +func StringToTimestamp(s string) pgtype.Timestamp { + if s == "" { + return pgtype.Timestamp{Valid: false} + } + + var t time.Time + var err error + + layouts := []string{ + "2006-01-02 15:04:05", // 完整时间 + "2006-01-02", // 仅日期也可解析 + } + + for _, layout := range layouts { + t, err = time.Parse(layout, s) + if err == nil { + return pgtype.Timestamp{ + Time: t, + Valid: true, + } + } + } + + return pgtype.Timestamp{Valid: false} +} + +// StringToDate 将字符串解析为 pgtype.Date +// 支持格式:YYYY-MM-DD +// 解析失败或空字符串返回零值 Date +func StringToDate(s string) pgtype.Date { + if s == "" { + return pgtype.Date{Valid: false} + } + + t, err := time.Parse("2006-01-02", s) + if err != nil { + return pgtype.Date{Valid: false} + } + + return pgtype.Date{ + Time: t, + Valid: true, + } +} + +func TimestampToMillis(ts pgtype.Timestamp) int64 { + return ts.Time.UnixMilli() +} + +func TimestamptzToMillis(ts pgtype.Timestamptz) int64 { + if !ts.Valid { + return 0 + } + return ts.Time.UnixMilli() +} + +func DateToString(d pgtype.Date) string { + if !d.Valid { + return "" + } + return d.Time.Format("2006-01-02") +} + +func Int32ToPgInt4(value int32) pgtype.Int4 { + return pgtype.Int4{ + Int32: value, + Valid: true, + } +} + +func TimePtrToPgDate(t *time.Time) pgtype.Date { + if t == nil { + return pgtype.Date{Valid: false} // ⭐ SQL NULL → 不限时间 + } + return pgtype.Date{ + Time: *t, // ⭐ 关键:解引用 + Valid: true, + } +} diff --git a/code/allapp/allapp-go/utils/redisx/helper.go b/code/allapp/allapp-go/utils/redisx/helper.go new file mode 100644 index 00000000..54d07c68 --- /dev/null +++ b/code/allapp/allapp-go/utils/redisx/helper.go @@ -0,0 +1,95 @@ +package redisx + +import ( + "context" + "errors" + "fmt" + "strconv" + + "github.com/redis/go-redis/v9" +) + +// 统一 key 生成函数 +func spaceMemberKey(spaceID int64) string { + return fmt.Sprintf("space:member:%d", spaceID) +} + +// SpaceAddOrUpdateMember 添加 / 更新成员角色 +func SpaceAddOrUpdateMember(spaceID int64, userID int64, role int) error { + key := spaceMemberKey(spaceID) + + return Client.HSet( + context.Background(), + key, + strconv.FormatInt(userID, 10), + role, + ).Err() +} + +// SpaceRemoveMember 删除成员 +func SpaceRemoveMember(spaceID int64, userID int64) error { + key := spaceMemberKey(spaceID) + + return Client.HDel( + context.Background(), + key, + strconv.FormatInt(userID, 10), + ).Err() +} + +// SpaceGetUserRole 获取成员角色 +func SpaceGetUserRole(spaceID int64, userID int64) (int, bool, error) { + key := spaceMemberKey(spaceID) + + val, err := Client.HGet( + context.Background(), + key, + strconv.FormatInt(userID, 10), + ).Result() + + if errors.Is(err, redis.Nil) { + return 0, false, nil + } + if err != nil { + return 0, false, err + } + + role, err := strconv.Atoi(val) + if err != nil { + return 0, false, err + } + + return role, true, nil +} + +// SpaceIsMember 判断是否在空间 +func SpaceIsMember(spaceID int64, userID int64) (bool, error) { + _, ok, err := SpaceGetUserRole(spaceID, userID) + return ok, err +} + +// SpaceInitMembers 初始化用户成员 +func SpaceInitMembers(spaceID int64, members map[int64]int) error { + key := spaceMemberKey(spaceID) + + data := make(map[string]interface{}) + for userID, role := range members { + data[strconv.FormatInt(userID, 10)] = role + } + + return Client.HSet( + context.Background(), + key, + data, + ).Err() +} + +// SpaceDelete 删除空间 +func SpaceDelete(spaceID int64) error { + key := spaceMemberKey(spaceID) + + return Client.Del( + context.Background(), + key, + ).Err() +} diff --git a/code/allapp/allapp-go/utils/redisx/index.go b/code/allapp/allapp-go/utils/redisx/index.go new file mode 100644 index 00000000..843dcdd6 --- /dev/null +++ b/code/allapp/allapp-go/utils/redisx/index.go @@ -0,0 +1,40 @@ +package redisx + +import ( + "context" + "errors" + "time" + + "github.com/redis/go-redis/v9" +) + +var ( + Client *redis.Client +) + +func Set(key string, value interface{}, expire time.Duration) error { + return Client.Set(context.Background(), key, value, expire).Err() +} + +// Get 获取任意 key 的值,返回 string +func Get(key string) (string, error) { + val, err := Client.Get(context.Background(), key).Result() + if errors.Is(err, redis.Nil) { + return "", nil + } + return val, err +} + +// Delete 删除任意 key +func Delete(key string) error { + return Client.Del(context.Background(), key).Err() +} + +// Exists 判断 key 是否存在 +func Exists(key string) (bool, error) { + cnt, err := Client.Exists(context.Background(), key).Result() + if err != nil { + return false, err + } + return cnt > 0, nil +} diff --git a/code/allapp/allapp-go/utils/requestx/index.go b/code/allapp/allapp-go/utils/requestx/index.go new file mode 100644 index 00000000..6e6d1494 --- /dev/null +++ b/code/allapp/allapp-go/utils/requestx/index.go @@ -0,0 +1,22 @@ +package requestx + +import ( + "allapp/utils/responsex" + "errors" + + "github.com/go-playground/validator/v10" + "github.com/gofiber/fiber/v3" +) + +// BindAndValidate 封装请求体解析和校验 +func BindAndValidate(c fiber.Ctx, v any) error { + if err := c.Bind().Body(v); err != nil { + // Handle validation errors + var validationErrors validator.ValidationErrors + if errors.As(err, &validationErrors) { + return responsex.Error(c, "参数校验失败") + } + return err + } + return nil +} diff --git a/code/allapp/allapp-go/utils/responsex/index.go b/code/allapp/allapp-go/utils/responsex/index.go index a039194b..4201d36c 100644 --- a/code/allapp/allapp-go/utils/responsex/index.go +++ b/code/allapp/allapp-go/utils/responsex/index.go @@ -1 +1,72 @@ package responsex + +import "github.com/gofiber/fiber/v3" + +// Result 响应结构 +type Result struct { + Code int `json:"code"` + Message string `json:"message"` + Data interface{} `json:"data"` + TrackId string `json:"trackId,omitempty"` +} + +// 业务码 +var BizCode = struct { + Success int // 成功 + Unauthorized int // 未授权/Token失效 + SpaceError int // 空间异常(已退出/被踢出等) + BusinessError int // 业务异常,例如参数错误、操作不允许 + SystemError int // 系统异常,例如数据库崩溃、未知错误 +}{ + Success: 1000, + Unauthorized: 1001, + SpaceError: 1002, + BusinessError: 2000, + SystemError: 3000, +} + +// ------------------- 统一响应方法 ------------------- + +// Respond 返回通用响应,code和msg必填,data可选 +func Respond(c fiber.Ctx, code int, msg string, data interface{}) error { + trackId := "" + if v := c.Context().Value("request_id"); v != nil { + if s, ok := v.(string); ok { + trackId = s + } + } + + return c.JSON(Result{ + Code: code, + Message: msg, + Data: data, + TrackId: trackId, + }) +} + +// ------------------- 便捷封装 ------------------- + +// OK 成功响应 +func OK(c fiber.Ctx, data interface{}) error { + return Respond(c, BizCode.Success, "success", data) +} + +// Error 业务异常 +func Error(c fiber.Ctx, msg string) error { + return Respond(c, BizCode.BusinessError, msg, nil) +} + +// SystemError 系统异常 +func SystemError(c fiber.Ctx, msg string) error { + return Respond(c, BizCode.SystemError, msg, nil) +} + +// Unauthorized 授权失败 +func Unauthorized(c fiber.Ctx, msg string) error { + return Respond(c, BizCode.Unauthorized, msg, nil) +} + +// SpaceError 空间异常 +func SpaceError(c fiber.Ctx, msg string) error { + return Respond(c, BizCode.SpaceError, msg, nil) +} diff --git a/code/allapp/allapp-go2/biz/handler/auth/login_service.go b/code/allapp/allapp-go2/biz/handler/auth/login_service.go index 7a005edd..8fb23720 100644 --- a/code/allapp/allapp-go2/biz/handler/auth/login_service.go +++ b/code/allapp/allapp-go2/biz/handler/auth/login_service.go @@ -224,6 +224,7 @@ func registerUser(ctx context.Context, c *app.RequestContext, openid, nickname, Username: nickname, Avatar: avatar, } + response.Success(c).Data(resp).Send() } diff --git a/code/allapp/allapp-go2/biz/router/middleware/auth.go b/code/allapp/allapp-go2/biz/router/middleware/auth.go index 2e7ba416..db233f08 100644 --- a/code/allapp/allapp-go2/biz/router/middleware/auth.go +++ b/code/allapp/allapp-go2/biz/router/middleware/auth.go @@ -52,6 +52,7 @@ func Auth() app.HandlerFunc { user := &ContextUser{ UserID: userID, } + ctx = setContextUser(ctx, user) c.Next(ctx) diff --git a/code/allapp/allapp-go2/db/queries/space.sql b/code/allapp/allapp-go2/db/queries/space.sql index ae9ba1d3..7c4b6ba8 100644 --- a/code/allapp/allapp-go2/db/queries/space.sql +++ b/code/allapp/allapp-go2/db/queries/space.sql @@ -12,7 +12,6 @@ DELETE FROM space WHERE id = $1; -- name: GetSpaceById :one SELECT * FROM space WHERE id = $1; - -- 查询用户所在的空间信息 -- name: GetSpaceByUserId :one SELECT s.*, m.role