commit b2871ec0d2097cc0f5ef61b4943fa458e2735c5f Author: denghui <1016848185@qq.com> Date: Thu Jul 10 21:04:29 2025 +0800 初始化项目框架,完成部分接口开发 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..18646b6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +.buildpath +.hgignore.swp +.project +.orig +.swp +.idea/ +.settings/ +.vscode/ +bin/ +**/.DS_Store +gf +main +main.exe +output/ +manifest/output/ +temp/ +temp.yaml +bin +**/config/config.yaml \ No newline at end of file diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..d36cedd --- /dev/null +++ b/README.MD @@ -0,0 +1,4 @@ +# GoFrame Template For SingleRepo + +Quick Start: +- https://goframe.org/quick \ No newline at end of file diff --git a/api/admin/admin.go b/api/admin/admin.go new file mode 100644 index 0000000..3d66157 --- /dev/null +++ b/api/admin/admin.go @@ -0,0 +1,16 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package admin + +import ( + "context" + + "server/api/admin/v1" +) + +type IAdminV1 interface { + AdminInfo(ctx context.Context, req *v1.AdminInfoReq) (res *v1.AdminInfoRes, err error) + AdminEditPass(ctx context.Context, req *v1.AdminEditPassReq) (res *v1.AdminEditPassRes, err error) +} diff --git a/api/admin/v1/admin.go b/api/admin/v1/admin.go new file mode 100644 index 0000000..ad0adc5 --- /dev/null +++ b/api/admin/v1/admin.go @@ -0,0 +1,24 @@ +package v1 + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +type AdminInfoReq struct { + g.Meta `path:"/admin/info" tags:"Admin" method:"get" summary:"管理员信息"` +} +type AdminInfoRes struct { + g.Meta `mime:"application/json"` + AdminId int64 `json:"adminId"` + Username string `json:"username"` +} + +type AdminEditPassReq struct { + g.Meta `path:"/admin/editPass" tags:"Admin" method:"post" summary:"修改密码"` + OldPass string `json:"oldPass" v:"required" dc:"旧密码"` + NewPass string `json:"newPass" v:"required" dc:"新密码"` +} +type AdminEditPassRes struct { + g.Meta `mime:"application/json"` + Success bool +} diff --git a/api/auth/auth.go b/api/auth/auth.go new file mode 100644 index 0000000..64d3473 --- /dev/null +++ b/api/auth/auth.go @@ -0,0 +1,19 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package auth + +import ( + "context" + + "server/api/auth/v1" +) + +type IAuthV1 interface { + AdminLogin(ctx context.Context, req *v1.AdminLoginReq) (res *v1.AdminLoginRes, err error) + UserLogin(ctx context.Context, req *v1.UserLoginReq) (res *v1.UserLoginRes, err error) + UserRegister(ctx context.Context, req *v1.UserRegisterReq) (res *v1.UserRegisterRes, err error) + UserEditPass(ctx context.Context, req *v1.UserEditPassReq) (res *v1.UserEditPassRes, err error) + UserCode(ctx context.Context, req *v1.UserCodeReq) (res *v1.UserCodeRes, err error) +} diff --git a/api/auth/v1/auth.go b/api/auth/v1/auth.go new file mode 100644 index 0000000..a4123d8 --- /dev/null +++ b/api/auth/v1/auth.go @@ -0,0 +1,47 @@ +package v1 + +import "github.com/gogf/gf/v2/frame/g" + +type AdminLoginReq struct { + g.Meta `path:"/admin/login" tags:"Admin" method:"post" summary:"管理员登录"` + Username string `json:"username" v:"required" dc:"用户名"` + Password string `json:"password" v:"required" dc:"密码"` +} +type AdminLoginRes struct { + Token string `json:"token" dc:"token"` +} +type UserLoginReq struct { + g.Meta `path:"/user/login" tags:"APP/User" method:"post" summary:"用户登录"` + Email string `json:"email" v:"required" dc:"邮箱"` + Password string `json:"password" v:"required" dc:"密码"` +} +type UserLoginRes struct { + Token string `json:"token" dc:"token"` +} +type UserRegisterReq struct { + g.Meta `path:"/user/register" tags:"APP/User" method:"post" summary:"用户注册"` + Email string `json:"email" v:"required" dc:"邮箱"` + Password string `json:"password" v:"required" dc:"密码"` + Password2 string `json:"password2" v:"required|same:password" dc:"确认密码"` +} +type UserRegisterRes struct { + Success bool `json:"success" dc:"是否成功"` +} +type UserEditPassReq struct { + g.Meta `path:"/user/editPass" tags:"APP/User" method:"post" summary:"修改密码"` + Email string `json:"email" v:"required" dc:"邮箱"` + Password string `json:"password" v:"required" dc:"密码"` + Password2 string `json:"password2" v:"required|same:password" dc:"确认密码"` + Sign string `json:"sign" v:"required" dc:"验证码"` +} + +type UserEditPassRes struct { + Success bool `json:"success" dc:"是否成功"` +} +type UserCodeReq struct { + g.Meta `path:"/user/code" tags:"APP/User" method:"post" summary:"获取验证码"` + Email string `json:"email" v:"required" dc:"邮箱"` +} +type UserCodeRes struct { + Success bool `json:"success" dc:"是否成功"` +} diff --git a/api/book/book.go b/api/book/book.go new file mode 100644 index 0000000..8afb24e --- /dev/null +++ b/api/book/book.go @@ -0,0 +1,18 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package book + +import ( + "context" + + "server/api/book/v1" +) + +type IBookV1 interface { + BookList(ctx context.Context, req *v1.BookListReq) (res *v1.BookListRes, err error) + BookAdd(ctx context.Context, req *v1.BookAddReq) (res *v1.BookAddRes, err error) + BookEdit(ctx context.Context, req *v1.BookEditReq) (res *v1.BookEditRes, err error) + BookDel(ctx context.Context, req *v1.BookDelReq) (res *v1.BookDelRes, err error) +} diff --git a/api/book/v1/book.go b/api/book/v1/book.go new file mode 100644 index 0000000..3974543 --- /dev/null +++ b/api/book/v1/book.go @@ -0,0 +1,61 @@ +package v1 + +import ( + "server/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type BookListReq struct { + g.Meta `path:"/book" tags:"Book" method:"get" summary:"获取小说列表"` + Page int `json:"page"` + Size int `json:"size"` + Title string `json:"title"` + CategoryId int64 `json:"categoryId"` + AuthorId int64 `json:"authorId"` + Status int `json:"status"` + IsRecommended int `json:"isRecommended"` +} +type BookListRes struct { + Total int `json:"total"` + List []model.Book `json:"list"` +} + +type BookAddReq struct { + g.Meta `path:"/book" tags:"Book" method:"post" summary:"新增小说"` + AuthorId int64 `json:"authorId"` + CategoryId int64 `json:"categoryId"` + Title string `json:"title"` + CoverUrl string `json:"coverUrl"` + Description string `json:"description"` + Status int `json:"status"` + Tags string `json:"tags"` + IsRecommended int `json:"isRecommended"` +} +type BookAddRes struct { + Success bool `json:"success"` +} + +type BookEditReq struct { + g.Meta `path:"/book" tags:"Book" method:"put" summary:"编辑小说"` + Id int64 `json:"id"` + AuthorId int64 `json:"authorId"` + CategoryId int64 `json:"categoryId"` + Title string `json:"title"` + CoverUrl string `json:"coverUrl"` + Description string `json:"description"` + Status int `json:"status"` + Tags string `json:"tags"` + IsRecommended int `json:"isRecommended"` +} +type BookEditRes struct { + Success bool `json:"success"` +} + +type BookDelReq struct { + g.Meta `path:"/book" tags:"Book" method:"delete" summary:"删除小说"` + Id int64 `json:"id"` +} +type BookDelRes struct { + Success bool `json:"success"` +} diff --git a/api/category/category.go b/api/category/category.go new file mode 100644 index 0000000..8cefcb1 --- /dev/null +++ b/api/category/category.go @@ -0,0 +1,18 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package category + +import ( + "context" + + "server/api/category/v1" +) + +type ICategoryV1 interface { + CategoryList(ctx context.Context, req *v1.CategoryListReq) (res *v1.CategoryListRes, err error) + CategoryAdd(ctx context.Context, req *v1.CategoryAddReq) (res *v1.CategoryAddRes, err error) + CategoryEdit(ctx context.Context, req *v1.CategoryEditReq) (res *v1.CategoryEditRes, err error) + CategoryDel(ctx context.Context, req *v1.CategoryDelReq) (res *v1.CategoryDelRes, err error) +} diff --git a/api/category/v1/category.go b/api/category/v1/category.go new file mode 100644 index 0000000..01aeaf9 --- /dev/null +++ b/api/category/v1/category.go @@ -0,0 +1,46 @@ +package v1 + +import ( + "server/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type CategoryListReq struct { + g.Meta `path:"/category" tags:"Category" method:"get" summary:"获取分类列表"` + Page int `json:"page" dc:"页码"` + Size int `json:"size" dc:"每页数量"` + Name string `json:"name" dc:"分类名称(模糊搜索)"` + Type int `json:"type" dc:"类型,1男频,2女频"` +} +type CategoryListRes struct { + Total int `json:"total" dc:"总数"` + List []model.Category `json:"list" dc:"分类列表"` +} + +type CategoryAddReq struct { + g.Meta `path:"/category" tags:"Category" method:"post" summary:"新增分类"` + Name string `json:"name" dc:"分类名称"` + Type int `json:"type" dc:"类型,1男频,2女频"` +} +type CategoryAddRes struct { + Success bool `json:"success" dc:"是否成功"` +} + +type CategoryEditReq struct { + g.Meta `path:"/category" tags:"Category" method:"put" summary:"编辑分类"` + Id int `json:"id" dc:"分类ID"` + Name string `json:"name" dc:"分类名称"` + Type int `json:"type" dc:"类型,1男频,2女频"` +} +type CategoryEditRes struct { + Success bool `json:"success" dc:"是否成功"` +} + +type CategoryDelReq struct { + g.Meta `path:"/category" tags:"Category" method:"delete" summary:"删除分类"` + Id int `json:"id" dc:"分类ID"` +} +type CategoryDelRes struct { + Success bool `json:"success" dc:"是否成功"` +} diff --git a/api/chapter/chapter.go b/api/chapter/chapter.go new file mode 100644 index 0000000..71ae89f --- /dev/null +++ b/api/chapter/chapter.go @@ -0,0 +1,18 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package chapter + +import ( + "context" + + "server/api/chapter/v1" +) + +type IChapterV1 interface { + ChapterList(ctx context.Context, req *v1.ChapterListReq) (res *v1.ChapterListRes, err error) + ChapterAdd(ctx context.Context, req *v1.ChapterAddReq) (res *v1.ChapterAddRes, err error) + ChapterEdit(ctx context.Context, req *v1.ChapterEditReq) (res *v1.ChapterEditRes, err error) + ChapterDel(ctx context.Context, req *v1.ChapterDelReq) (res *v1.ChapterDelRes, err error) +} diff --git a/api/chapter/v1/chapter.go b/api/chapter/v1/chapter.go new file mode 100644 index 0000000..6c42daa --- /dev/null +++ b/api/chapter/v1/chapter.go @@ -0,0 +1,57 @@ +package v1 + +import ( + "server/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type ChapterListReq struct { + g.Meta `path:"/chapter" tags:"Chapter" method:"get" summary:"获取章节列表"` + Page int `json:"page" dc:"页码"` + Size int `json:"size" dc:"每页数量"` + BookId int64 `json:"bookId" dc:"小说ID"` + Title string `json:"title" dc:"章节标题(模糊搜索)"` + IsLocked int `json:"isLocked" dc:"是否锁定:0免费,1需积分解锁"` +} +type ChapterListRes struct { + Total int `json:"total" dc:"总数"` + List []model.Chapter `json:"list" dc:"章节列表"` +} + +type ChapterAddReq struct { + g.Meta `path:"/chapter" tags:"Chapter" method:"post" summary:"新增章节"` + BookId int64 `json:"bookId" dc:"小说ID"` + Title string `json:"title" dc:"章节标题"` + Content string `json:"content" dc:"章节内容"` + WordCount int `json:"wordCount" dc:"章节字数"` + Sort int `json:"sort" dc:"排序序号"` + IsLocked int `json:"isLocked" dc:"是否锁定:0免费,1需积分解锁"` + RequiredScore int `json:"requiredScore" dc:"解锁所需积分"` +} +type ChapterAddRes struct { + Success bool `json:"success" dc:"是否成功"` +} + +type ChapterEditReq struct { + g.Meta `path:"/chapter" tags:"Chapter" method:"put" summary:"编辑章节"` + Id int64 `json:"id" dc:"章节ID"` + BookId int64 `json:"bookId" dc:"小说ID"` + Title string `json:"title" dc:"章节标题"` + Content string `json:"content" dc:"章节内容"` + WordCount int `json:"wordCount" dc:"章节字数"` + Sort int `json:"sort" dc:"排序序号"` + IsLocked int `json:"isLocked" dc:"是否锁定:0免费,1需积分解锁"` + RequiredScore int `json:"requiredScore" dc:"解锁所需积分"` +} +type ChapterEditRes struct { + Success bool `json:"success" dc:"是否成功"` +} + +type ChapterDelReq struct { + g.Meta `path:"/chapter" tags:"Chapter" method:"delete" summary:"删除章节"` + Id int64 `json:"id" dc:"章节ID"` +} +type ChapterDelRes struct { + Success bool `json:"success" dc:"是否成功"` +} diff --git a/api/feedback/feedback.go b/api/feedback/feedback.go new file mode 100644 index 0000000..b8f023e --- /dev/null +++ b/api/feedback/feedback.go @@ -0,0 +1,16 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package feedback + +import ( + "context" + + "server/api/feedback/v1" +) + +type IFeedbackV1 interface { + FeedbackList(ctx context.Context, req *v1.FeedbackListReq) (res *v1.FeedbackListRes, err error) + FeedbackAdd(ctx context.Context, req *v1.FeedbackAddReq) (res *v1.FeedbackAddRes, err error) +} diff --git a/api/feedback/v1/feedback.go b/api/feedback/v1/feedback.go new file mode 100644 index 0000000..0e96c86 --- /dev/null +++ b/api/feedback/v1/feedback.go @@ -0,0 +1,27 @@ +package v1 + +import ( + "server/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type FeedbackListReq struct { + g.Meta `path:"/feedback" tags:"Feedback" method:"get" summary:"获取反馈列表"` + Page int `json:"page" dc:"页码"` + Size int `json:"size" dc:"每页数量"` + UserId int64 `json:"userId" dc:"用户ID"` + Status int `json:"status" dc:"处理状态:1未处理,2处理中,3已处理"` +} +type FeedbackListRes struct { + Total int `json:"total" dc:"总数"` + List []model.Feedback `json:"list" dc:"反馈列表"` +} + +type FeedbackAddReq struct { + g.Meta `path:"/feedback" tags:"APP/Feedback" method:"post" summary:"新增反馈"` + Content string `json:"content" dc:"反馈内容"` +} +type FeedbackAddRes struct { + Success bool `json:"success" dc:"是否成功"` +} diff --git a/api/user/user.go b/api/user/user.go new file mode 100644 index 0000000..3883b6b --- /dev/null +++ b/api/user/user.go @@ -0,0 +1,17 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package user + +import ( + "context" + + "server/api/user/v1" +) + +type IUserV1 interface { + UserInfo(ctx context.Context, req *v1.UserInfoReq) (res *v1.UserInfoRes, err error) + Delete(ctx context.Context, req *v1.DeleteReq) (res *v1.DeleteRes, err error) + Logout(ctx context.Context, req *v1.LogoutReq) (res *v1.LogoutRes, err error) +} diff --git a/api/user/v1/user.go b/api/user/v1/user.go new file mode 100644 index 0000000..2bdd916 --- /dev/null +++ b/api/user/v1/user.go @@ -0,0 +1,33 @@ +package v1 + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +type UserInfoReq struct { + g.Meta `path:"/user/info" tags:"APP/User" method:"get" summary:"获取用户信息"` +} +type UserInfoRes struct { + g.Meta `mime:"application/json"` + UserId int64 `json:"userId"` + Username string `json:"username"` // 用户名 + Avatar string `json:"avatar"` // 头像 URL + Email string `json:"email"` // 邮箱 + Points uint64 `json:"points"` +} + +type DeleteReq struct { + g.Meta `path:"/user/delete" tags:"APP/User" method:"post" summary:"删除用户"` + Password string `json:"password" v:"required" dc:"密码"` +} + +type DeleteRes struct { + Success bool `json:"success" dc:"是否成功"` +} + +type LogoutReq struct { + g.Meta `path:"/user/logout" tags:"APP/User" method:"post" summary:"登出"` +} +type LogoutRes struct { + Success bool `json:"success" dc:"是否成功"` +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..a44bc69 --- /dev/null +++ b/go.mod @@ -0,0 +1,53 @@ +module server + +go 1.23.0 + +toolchain go1.24.3 + +require ( + github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible + github.com/casbin/casbin/v2 v2.108.0 + github.com/gogf/gf v1.16.9 + github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.0 + github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.0 + github.com/gogf/gf/v2 v2.9.0 + github.com/golang-jwt/jwt/v5 v5.2.2 + github.com/google/uuid v1.6.0 + github.com/hailaz/gf-casbin-adapter/v2 v2.8.1 + golang.org/x/crypto v0.30.0 +) + +require ( + github.com/BurntSushi/toml v1.4.0 // indirect + github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect + github.com/casbin/govaluate v1.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 // indirect + github.com/clbanning/mxj/v2 v2.7.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/emirpasic/gods v1.18.1 // indirect + github.com/fatih/color v1.18.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-sql-driver/mysql v1.7.1 // indirect + github.com/gomodule/redigo v1.8.5 // indirect + github.com/gorilla/websocket v1.5.3 // indirect + github.com/grokify/html-strip-tags-go v0.1.0 // indirect + github.com/magiconair/properties v1.8.9 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/redis/go-redis/v9 v9.7.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect + golang.org/x/net v0.32.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.12.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..c6c3839 --- /dev/null +++ b/go.sum @@ -0,0 +1,147 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g= +github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= +github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I= +github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/casbin/casbin/v2 v2.108.0 h1:aMc3I81wfLpQe/uzMdElB1OBhEmPZoWMPb2nfEaKygY= +github.com/casbin/casbin/v2 v2.108.0/go.mod h1:Ee33aqGrmES+GNL17L0h9X28wXuo829wnNUnS0edAco= +github.com/casbin/govaluate v1.3.0 h1:VA0eSY0M2lA86dYd5kPPuNZMUD9QkWnOCnavGrw9myc= +github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A= +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/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 h1:LdXxtjzvZYhhUaonAaAKArG3pyC67kGL3YY+6hGG8G4= +github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= +github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= +github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/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/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= +github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/gogf/gf v1.16.9 h1:Q803UmmRo59+Ws08sMVFOcd8oNpkSWL9vS33hlo/Cyk= +github.com/gogf/gf v1.16.9/go.mod h1:8Q/kw05nlVRp+4vv7XASBsMe9L1tsVKiGoeP2AHnlkk= +github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.0 h1:1f7EeD0lfPHoXfaJDSL7cxRcSRelbsAKgF3MGXY+Uyo= +github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.0/go.mod h1:tToO1PjGkLIR+9DbJ0wrKicYma0H/EUHXOpwel6Dw+0= +github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.0 h1:EEZqu1PNRSmm+7Cqm9A/8+ObgfbMzhE1ps9Z3LD7HgM= +github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.0/go.mod h1:LHrxY+2IzNTHVTPG/s5yaz1VmXbj+CQ7Hr5SeVkHiTw= +github.com/gogf/gf/v2 v2.9.0 h1:semN5Q5qGjDQEv4620VzxcJzJlSD07gmyJ9Sy9zfbHk= +github.com/gogf/gf/v2 v2.9.0/go.mod h1:sWGQw+pLILtuHmbOxoe0D+0DdaXxbleT57axOLH2vKI= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc= +github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +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/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78= +github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= +github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= +github.com/hailaz/gf-casbin-adapter/v2 v2.8.1 h1:ZFIlfQAYmrL2Fe6/dZz6vCA5hYK0NxhnoKMQpbklgqc= +github.com/hailaz/gf-casbin-adapter/v2 v2.8.1/go.mod h1:Jk91dRBZuMVjBMu2oQmqMRc6xuL5V+rzgHeFWvI+wlg= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= +github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= +github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= +golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= +golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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/hack/config.yaml b/hack/config.yaml new file mode 100644 index 0000000..d033627 --- /dev/null +++ b/hack/config.yaml @@ -0,0 +1,9 @@ + +# CLI tool, only in development environment. +# https://goframe.org/docs/cli +gfcli: + gen: + dao: + - link: "mysql:root:MSms0427@tcp(127.0.0.1:3306)/novel" + descriptionTag: true + tablesEx: "casbin_rule" \ No newline at end of file diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go new file mode 100644 index 0000000..22180fa --- /dev/null +++ b/internal/cmd/cmd.go @@ -0,0 +1,50 @@ +package cmd + +import ( + "context" + "server/internal/controller/admin" + "server/internal/controller/auth" + "server/internal/controller/book" + "server/internal/controller/category" + "server/internal/controller/chapter" + "server/internal/controller/feedback" + "server/internal/controller/user" + "server/internal/middleware" + + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/os/gcmd" +) + +var ( + Main = gcmd.Command{ + Name: "main", + Usage: "main", + Brief: "start http server", + Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { + s := g.Server() + s.Group("/", func(group *ghttp.RouterGroup) { + group.Middleware(middleware.Language) // 语言检测中间件 + group.Middleware(middleware.Response) + group.Middleware(ghttp.MiddlewareCORS) + group.Bind( + auth.NewV1(), + ) + group.Group("/", func(group *ghttp.RouterGroup) { + group.Middleware(middleware.Auth) + group.Middleware(middleware.Casbin) + group.Bind( + admin.NewV1(), + book.NewV1(), + category.NewV1(), + chapter.NewV1(), + feedback.NewV1(), + user.NewV1(), + ) + }) + }) + s.Run() + return nil + }, + } +) diff --git a/internal/consts/consts.go b/internal/consts/consts.go new file mode 100644 index 0000000..d709a2b --- /dev/null +++ b/internal/consts/consts.go @@ -0,0 +1 @@ +package consts diff --git a/internal/consts/role.go b/internal/consts/role.go new file mode 100644 index 0000000..ee1ddf9 --- /dev/null +++ b/internal/consts/role.go @@ -0,0 +1,8 @@ +package consts + +const ( + GuestRoleCode = "guest" + UserRoleCode = "user" + AuthorRoleCode = "author" + AdminRoleCode = "admin" +) diff --git a/internal/consts/user.go b/internal/consts/user.go new file mode 100644 index 0000000..93726a9 --- /dev/null +++ b/internal/consts/user.go @@ -0,0 +1,6 @@ +package consts + +const ( + UserEnable = iota + 1 + UserDisable +) diff --git a/internal/controller/admin/admin.go b/internal/controller/admin/admin.go new file mode 100644 index 0000000..f122676 --- /dev/null +++ b/internal/controller/admin/admin.go @@ -0,0 +1,5 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package admin diff --git a/internal/controller/admin/admin_new.go b/internal/controller/admin/admin_new.go new file mode 100644 index 0000000..ec91d7a --- /dev/null +++ b/internal/controller/admin/admin_new.go @@ -0,0 +1,15 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package admin + +import ( + "server/api/admin" +) + +type ControllerV1 struct{} + +func NewV1() admin.IAdminV1 { + return &ControllerV1{} +} diff --git a/internal/controller/admin/admin_v1_admin_edit_pass.go b/internal/controller/admin/admin_v1_admin_edit_pass.go new file mode 100644 index 0000000..8f99345 --- /dev/null +++ b/internal/controller/admin/admin_v1_admin_edit_pass.go @@ -0,0 +1,17 @@ +package admin + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/admin/v1" +) + +func (c *ControllerV1) AdminEditPass(ctx context.Context, req *v1.AdminEditPassReq) (res *v1.AdminEditPassRes, err error) { + out, err := service.Admin().EditPass(ctx, &model.AdminEditPassIn{NewPass: req.NewPass, OldPass: req.OldPass}) + if err != nil { + return nil, err + } + return &v1.AdminEditPassRes{Success: out.Success}, nil +} diff --git a/internal/controller/admin/admin_v1_admin_info.go b/internal/controller/admin/admin_v1_admin_info.go new file mode 100644 index 0000000..883aac6 --- /dev/null +++ b/internal/controller/admin/admin_v1_admin_info.go @@ -0,0 +1,22 @@ +package admin + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "server/internal/model" + "server/internal/service" + + "server/api/admin/v1" +) + +func (c *ControllerV1) AdminInfo(ctx context.Context, req *v1.AdminInfoReq) (res *v1.AdminInfoRes, err error) { + adminId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64() + out, err := service.Admin().Info(ctx, &model.AdminInfoIn{AdminId: adminId}) + if err != nil { + return nil, err + } + return &v1.AdminInfoRes{ + AdminId: out.AdminId, + Username: out.Username, + }, nil +} diff --git a/internal/controller/auth/auth.go b/internal/controller/auth/auth.go new file mode 100644 index 0000000..52ff940 --- /dev/null +++ b/internal/controller/auth/auth.go @@ -0,0 +1,5 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package auth diff --git a/internal/controller/auth/auth_new.go b/internal/controller/auth/auth_new.go new file mode 100644 index 0000000..938b497 --- /dev/null +++ b/internal/controller/auth/auth_new.go @@ -0,0 +1,15 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package auth + +import ( + "server/api/auth" +) + +type ControllerV1 struct{} + +func NewV1() auth.IAuthV1 { + return &ControllerV1{} +} diff --git a/internal/controller/auth/auth_v1_admin_login.go b/internal/controller/auth/auth_v1_admin_login.go new file mode 100644 index 0000000..72ea37b --- /dev/null +++ b/internal/controller/auth/auth_v1_admin_login.go @@ -0,0 +1,17 @@ +package auth + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/auth/v1" +) + +func (c *ControllerV1) AdminLogin(ctx context.Context, req *v1.AdminLoginReq) (res *v1.AdminLoginRes, err error) { + out, err := service.Admin().Login(ctx, &model.AdminLoginIn{Username: req.Username, Password: req.Password}) + if err != nil { + return nil, err + } + return &v1.AdminLoginRes{Token: out.Token}, nil +} diff --git a/internal/controller/auth/auth_v1_user_code.go b/internal/controller/auth/auth_v1_user_code.go new file mode 100644 index 0000000..1e9401e --- /dev/null +++ b/internal/controller/auth/auth_v1_user_code.go @@ -0,0 +1,17 @@ +package auth + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/auth/v1" +) + +func (c *ControllerV1) UserCode(ctx context.Context, req *v1.UserCodeReq) (res *v1.UserCodeRes, err error) { + out, err := service.User().Code(ctx, &model.UserCodeIn{Email: req.Email}) + if err != nil { + return nil, err + } + return &v1.UserCodeRes{Success: out.Success}, nil +} diff --git a/internal/controller/auth/auth_v1_user_edit_pass.go b/internal/controller/auth/auth_v1_user_edit_pass.go new file mode 100644 index 0000000..ca4d631 --- /dev/null +++ b/internal/controller/auth/auth_v1_user_edit_pass.go @@ -0,0 +1,17 @@ +package auth + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/auth/v1" +) + +func (c *ControllerV1) UserEditPass(ctx context.Context, req *v1.UserEditPassReq) (res *v1.UserEditPassRes, err error) { + out, err := service.User().EditPass(ctx, &model.UserEditPassIn{Email: req.Email, Password: req.Password, Password2: req.Password2, Sign: req.Sign}) + if err != nil { + return nil, err + } + return &v1.UserEditPassRes{Success: out.Success}, nil +} diff --git a/internal/controller/auth/auth_v1_user_login.go b/internal/controller/auth/auth_v1_user_login.go new file mode 100644 index 0000000..70327ae --- /dev/null +++ b/internal/controller/auth/auth_v1_user_login.go @@ -0,0 +1,18 @@ +package auth + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/auth/v1" +) + +func (c *ControllerV1) UserLogin(ctx context.Context, req *v1.UserLoginReq) (res *v1.UserLoginRes, err error) { + out, err := service.User().Login(ctx, &model.UserLoginIn{Email: req.Email, Password: req.Password}) + if err != nil { + return nil, err + } + + return &v1.UserLoginRes{Token: out.Token}, nil +} diff --git a/internal/controller/auth/auth_v1_user_register.go b/internal/controller/auth/auth_v1_user_register.go new file mode 100644 index 0000000..3accd7f --- /dev/null +++ b/internal/controller/auth/auth_v1_user_register.go @@ -0,0 +1,17 @@ +package auth + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/auth/v1" +) + +func (c *ControllerV1) UserRegister(ctx context.Context, req *v1.UserRegisterReq) (res *v1.UserRegisterRes, err error) { + out, err := service.User().Register(ctx, &model.UserRegisterIn{Email: req.Email, Password: req.Password, Password2: req.Password2}) + if err != nil { + return nil, err + } + return &v1.UserRegisterRes{Success: out.Success}, nil +} diff --git a/internal/controller/book/book.go b/internal/controller/book/book.go new file mode 100644 index 0000000..8931452 --- /dev/null +++ b/internal/controller/book/book.go @@ -0,0 +1,5 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package book diff --git a/internal/controller/book/book_new.go b/internal/controller/book/book_new.go new file mode 100644 index 0000000..971f22a --- /dev/null +++ b/internal/controller/book/book_new.go @@ -0,0 +1,15 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package book + +import ( + "server/api/book" +) + +type ControllerV1 struct{} + +func NewV1() book.IBookV1 { + return &ControllerV1{} +} diff --git a/internal/controller/book/book_v1_book_add.go b/internal/controller/book/book_v1_book_add.go new file mode 100644 index 0000000..11eb037 --- /dev/null +++ b/internal/controller/book/book_v1_book_add.go @@ -0,0 +1,26 @@ +package book + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/book/v1" +) + +func (c *ControllerV1) BookAdd(ctx context.Context, req *v1.BookAddReq) (res *v1.BookAddRes, err error) { + out, err := service.Book().Create(ctx, &model.BookAddIn{ + AuthorId: req.AuthorId, + CategoryId: req.CategoryId, + CoverUrl: req.CoverUrl, + Description: req.Description, + IsRecommended: req.IsRecommended, + Status: req.Status, + Tags: req.Tags, + Title: req.Title, + }) + if err != nil { + return nil, err + } + return &v1.BookAddRes{Success: out.Success}, nil +} diff --git a/internal/controller/book/book_v1_book_del.go b/internal/controller/book/book_v1_book_del.go new file mode 100644 index 0000000..78efc66 --- /dev/null +++ b/internal/controller/book/book_v1_book_del.go @@ -0,0 +1,19 @@ +package book + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/book/v1" +) + +func (c *ControllerV1) BookDel(ctx context.Context, req *v1.BookDelReq) (res *v1.BookDelRes, err error) { + out, err := service.Book().Delete(ctx, &model.BookDelIn{ + Id: req.Id, + }) + if err != nil { + return nil, err + } + return &v1.BookDelRes{Success: out.Success}, nil +} diff --git a/internal/controller/book/book_v1_book_edit.go b/internal/controller/book/book_v1_book_edit.go new file mode 100644 index 0000000..0a2e443 --- /dev/null +++ b/internal/controller/book/book_v1_book_edit.go @@ -0,0 +1,27 @@ +package book + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/book/v1" +) + +func (c *ControllerV1) BookEdit(ctx context.Context, req *v1.BookEditReq) (res *v1.BookEditRes, err error) { + out, err := service.Book().Update(ctx, &model.BookEditIn{ + AuthorId: req.AuthorId, + CategoryId: req.CategoryId, + CoverUrl: req.CoverUrl, + Description: req.Description, + Id: req.Id, + IsRecommended: req.IsRecommended, + Status: req.Status, + Tags: req.Tags, + Title: req.Title, + }) + if err != nil { + return nil, err + } + return &v1.BookEditRes{Success: out.Success}, nil +} diff --git a/internal/controller/book/book_v1_book_list.go b/internal/controller/book/book_v1_book_list.go new file mode 100644 index 0000000..2fa3e2e --- /dev/null +++ b/internal/controller/book/book_v1_book_list.go @@ -0,0 +1,28 @@ +package book + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/book/v1" +) + +func (c *ControllerV1) BookList(ctx context.Context, req *v1.BookListReq) (res *v1.BookListRes, err error) { + out, err := service.Book().List(ctx, &model.BookListIn{ + AuthorId: req.AuthorId, + CategoryId: req.CategoryId, + IsRecommended: req.IsRecommended, + Page: req.Page, + Size: req.Size, + Status: req.Status, + Title: req.Title, + }) + if err != nil { + return nil, err + } + return &v1.BookListRes{ + List: out.List, + Total: out.Total, + }, nil +} diff --git a/internal/controller/category/category.go b/internal/controller/category/category.go new file mode 100644 index 0000000..a7b1a71 --- /dev/null +++ b/internal/controller/category/category.go @@ -0,0 +1,5 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package category diff --git a/internal/controller/category/category_new.go b/internal/controller/category/category_new.go new file mode 100644 index 0000000..963d435 --- /dev/null +++ b/internal/controller/category/category_new.go @@ -0,0 +1,15 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package category + +import ( + "server/api/category" +) + +type ControllerV1 struct{} + +func NewV1() category.ICategoryV1 { + return &ControllerV1{} +} diff --git a/internal/controller/category/category_v1_category_add.go b/internal/controller/category/category_v1_category_add.go new file mode 100644 index 0000000..fc1f93e --- /dev/null +++ b/internal/controller/category/category_v1_category_add.go @@ -0,0 +1,22 @@ +package category + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/category/v1" +) + +func (c *ControllerV1) CategoryAdd(ctx context.Context, req *v1.CategoryAddReq) (res *v1.CategoryAddRes, err error) { + out, err := service.Category().Create(ctx, &model.CategoryAddIn{ + Name: req.Name, + Type: req.Type, + }) + if err != nil { + return nil, err + } + return &v1.CategoryAddRes{ + Success: out.Success, + }, nil +} diff --git a/internal/controller/category/category_v1_category_del.go b/internal/controller/category/category_v1_category_del.go new file mode 100644 index 0000000..22407c0 --- /dev/null +++ b/internal/controller/category/category_v1_category_del.go @@ -0,0 +1,21 @@ +package category + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/category/v1" +) + +func (c *ControllerV1) CategoryDel(ctx context.Context, req *v1.CategoryDelReq) (res *v1.CategoryDelRes, err error) { + out, err := service.Category().Delete(ctx, &model.CategoryDelIn{ + Id: req.Id, + }) + if err != nil { + return nil, err + } + return &v1.CategoryDelRes{ + Success: out.Success, + }, nil +} diff --git a/internal/controller/category/category_v1_category_edit.go b/internal/controller/category/category_v1_category_edit.go new file mode 100644 index 0000000..440400a --- /dev/null +++ b/internal/controller/category/category_v1_category_edit.go @@ -0,0 +1,23 @@ +package category + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/category/v1" +) + +func (c *ControllerV1) CategoryEdit(ctx context.Context, req *v1.CategoryEditReq) (res *v1.CategoryEditRes, err error) { + out, err := service.Category().Update(ctx, &model.CategoryEditIn{ + Id: req.Id, + Name: req.Name, + Type: req.Type, + }) + if err != nil { + return nil, err + } + return &v1.CategoryEditRes{ + Success: out.Success, + }, nil +} diff --git a/internal/controller/category/category_v1_category_list.go b/internal/controller/category/category_v1_category_list.go new file mode 100644 index 0000000..890ad90 --- /dev/null +++ b/internal/controller/category/category_v1_category_list.go @@ -0,0 +1,25 @@ +package category + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/category/v1" +) + +func (c *ControllerV1) CategoryList(ctx context.Context, req *v1.CategoryListReq) (res *v1.CategoryListRes, err error) { + out, err := service.Category().List(ctx, &model.CategoryListIn{ + Name: req.Name, + Page: req.Page, + Size: req.Size, + Type: req.Type, + }) + if err != nil { + return nil, err + } + return &v1.CategoryListRes{ + List: out.List, + Total: out.Total, + }, nil +} diff --git a/internal/controller/chapter/chapter.go b/internal/controller/chapter/chapter.go new file mode 100644 index 0000000..6f174af --- /dev/null +++ b/internal/controller/chapter/chapter.go @@ -0,0 +1,5 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package chapter diff --git a/internal/controller/chapter/chapter_new.go b/internal/controller/chapter/chapter_new.go new file mode 100644 index 0000000..837226d --- /dev/null +++ b/internal/controller/chapter/chapter_new.go @@ -0,0 +1,15 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package chapter + +import ( + "server/api/chapter" +) + +type ControllerV1 struct{} + +func NewV1() chapter.IChapterV1 { + return &ControllerV1{} +} diff --git a/internal/controller/chapter/chapter_v1_chapter_add.go b/internal/controller/chapter/chapter_v1_chapter_add.go new file mode 100644 index 0000000..920aafe --- /dev/null +++ b/internal/controller/chapter/chapter_v1_chapter_add.go @@ -0,0 +1,27 @@ +package chapter + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/chapter/v1" +) + +func (c *ControllerV1) ChapterAdd(ctx context.Context, req *v1.ChapterAddReq) (res *v1.ChapterAddRes, err error) { + out, err := service.Chapter().Create(ctx, &model.ChapterAddIn{ + BookId: req.BookId, + Content: req.Content, + IsLocked: req.IsLocked, + RequiredScore: req.RequiredScore, + Sort: req.Sort, + Title: req.Title, + WordCount: req.WordCount, + }) + if err != nil { + return nil, err + } + return &v1.ChapterAddRes{ + Success: out.Success, + }, nil +} diff --git a/internal/controller/chapter/chapter_v1_chapter_del.go b/internal/controller/chapter/chapter_v1_chapter_del.go new file mode 100644 index 0000000..850be4c --- /dev/null +++ b/internal/controller/chapter/chapter_v1_chapter_del.go @@ -0,0 +1,19 @@ +package chapter + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/chapter/v1" +) + +func (c *ControllerV1) ChapterDel(ctx context.Context, req *v1.ChapterDelReq) (res *v1.ChapterDelRes, err error) { + out, err := service.Chapter().Delete(ctx, &model.ChapterDelIn{ + Id: req.Id, + }) + if err != nil { + return nil, err + } + return &v1.ChapterDelRes{Success: out.Success}, nil +} diff --git a/internal/controller/chapter/chapter_v1_chapter_edit.go b/internal/controller/chapter/chapter_v1_chapter_edit.go new file mode 100644 index 0000000..fc23813 --- /dev/null +++ b/internal/controller/chapter/chapter_v1_chapter_edit.go @@ -0,0 +1,28 @@ +package chapter + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/chapter/v1" +) + +func (c *ControllerV1) ChapterEdit(ctx context.Context, req *v1.ChapterEditReq) (res *v1.ChapterEditRes, err error) { + out, err := service.Chapter().Update(ctx, &model.ChapterEditIn{ + BookId: req.BookId, + Content: req.Content, + Id: req.Id, + IsLocked: req.IsLocked, + RequiredScore: req.RequiredScore, + Sort: req.Sort, + Title: req.Title, + WordCount: req.WordCount, + }) + if err != nil { + return nil, err + } + return &v1.ChapterEditRes{ + Success: out.Success, + }, nil +} diff --git a/internal/controller/chapter/chapter_v1_chapter_list.go b/internal/controller/chapter/chapter_v1_chapter_list.go new file mode 100644 index 0000000..8dad245 --- /dev/null +++ b/internal/controller/chapter/chapter_v1_chapter_list.go @@ -0,0 +1,26 @@ +package chapter + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/chapter/v1" +) + +func (c *ControllerV1) ChapterList(ctx context.Context, req *v1.ChapterListReq) (res *v1.ChapterListRes, err error) { + out, err := service.Chapter().List(ctx, &model.ChapterListIn{ + BookId: req.BookId, + IsLocked: req.IsLocked, + Page: req.Page, + Size: req.Size, + Title: req.Title, + }) + if err != nil { + return nil, err + } + return &v1.ChapterListRes{ + List: out.List, + Total: out.Total, + }, nil +} diff --git a/internal/controller/feedback/feedback.go b/internal/controller/feedback/feedback.go new file mode 100644 index 0000000..e65ec14 --- /dev/null +++ b/internal/controller/feedback/feedback.go @@ -0,0 +1,5 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package feedback diff --git a/internal/controller/feedback/feedback_new.go b/internal/controller/feedback/feedback_new.go new file mode 100644 index 0000000..49b09fd --- /dev/null +++ b/internal/controller/feedback/feedback_new.go @@ -0,0 +1,15 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package feedback + +import ( + "server/api/feedback" +) + +type ControllerV1 struct{} + +func NewV1() feedback.IFeedbackV1 { + return &ControllerV1{} +} diff --git a/internal/controller/feedback/feedback_v1_feedback_add.go b/internal/controller/feedback/feedback_v1_feedback_add.go new file mode 100644 index 0000000..67627cf --- /dev/null +++ b/internal/controller/feedback/feedback_v1_feedback_add.go @@ -0,0 +1,24 @@ +package feedback + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "server/internal/model" + "server/internal/service" + + "server/api/feedback/v1" +) + +func (c *ControllerV1) FeedbackAdd(ctx context.Context, req *v1.FeedbackAddReq) (res *v1.FeedbackAddRes, err error) { + userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64() + out, err := service.Feedback().Create(ctx, &model.FeedbackAddIn{ + Content: req.Content, + UserId: userId, + }) + if err != nil { + return nil, err + } + return &v1.FeedbackAddRes{ + Success: out.Success, + }, nil +} diff --git a/internal/controller/feedback/feedback_v1_feedback_list.go b/internal/controller/feedback/feedback_v1_feedback_list.go new file mode 100644 index 0000000..c61c4be --- /dev/null +++ b/internal/controller/feedback/feedback_v1_feedback_list.go @@ -0,0 +1,25 @@ +package feedback + +import ( + "context" + "server/internal/model" + "server/internal/service" + + "server/api/feedback/v1" +) + +func (c *ControllerV1) FeedbackList(ctx context.Context, req *v1.FeedbackListReq) (res *v1.FeedbackListRes, err error) { + out, err := service.Feedback().List(ctx, &model.FeedbackListIn{ + Page: req.Page, + Size: req.Size, + Status: req.Status, + UserId: req.UserId, + }) + if err != nil { + return nil, err + } + return &v1.FeedbackListRes{ + List: out.List, + Total: out.Total, + }, nil +} diff --git a/internal/controller/user/user.go b/internal/controller/user/user.go new file mode 100644 index 0000000..8220c1a --- /dev/null +++ b/internal/controller/user/user.go @@ -0,0 +1,5 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package user diff --git a/internal/controller/user/user_new.go b/internal/controller/user/user_new.go new file mode 100644 index 0000000..f54941d --- /dev/null +++ b/internal/controller/user/user_new.go @@ -0,0 +1,15 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package user + +import ( + "server/api/user" +) + +type ControllerV1 struct{} + +func NewV1() user.IUserV1 { + return &ControllerV1{} +} diff --git a/internal/controller/user/user_v1_delete.go b/internal/controller/user/user_v1_delete.go new file mode 100644 index 0000000..4ccfa13 --- /dev/null +++ b/internal/controller/user/user_v1_delete.go @@ -0,0 +1,19 @@ +package user + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "server/internal/model" + "server/internal/service" + + "server/api/user/v1" +) + +func (c *ControllerV1) Delete(ctx context.Context, req *v1.DeleteReq) (res *v1.DeleteRes, err error) { + userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64() + out, err := service.User().Delete(ctx, &model.UserDeleteIn{UserId: userId, Password: req.Password}) + if err != nil { + return nil, err + } + return &v1.DeleteRes{Success: out.Success}, nil +} diff --git a/internal/controller/user/user_v1_logout.go b/internal/controller/user/user_v1_logout.go new file mode 100644 index 0000000..5ee99aa --- /dev/null +++ b/internal/controller/user/user_v1_logout.go @@ -0,0 +1,14 @@ +package user + +import ( + "context" + + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + + "server/api/user/v1" +) + +func (c *ControllerV1) Logout(ctx context.Context, req *v1.LogoutReq) (res *v1.LogoutRes, err error) { + return nil, gerror.NewCode(gcode.CodeNotImplemented) +} diff --git a/internal/controller/user/user_v1_user_info.go b/internal/controller/user/user_v1_user_info.go new file mode 100644 index 0000000..6e17ff4 --- /dev/null +++ b/internal/controller/user/user_v1_user_info.go @@ -0,0 +1,24 @@ +package user + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "server/internal/model" + "server/internal/service" + + "server/api/user/v1" +) + +func (c *ControllerV1) UserInfo(ctx context.Context, req *v1.UserInfoReq) (res *v1.UserInfoRes, err error) { + userId := g.RequestFromCtx(ctx).GetCtxVar("id").Int64() + info, err := service.User().Info(ctx, &model.UserInfoIn{UserId: userId}) + if err != nil { + return nil, err + } + return &v1.UserInfoRes{ + Username: info.Username, + Avatar: info.Avatar, + Email: info.Email, + Points: info.Points, + }, nil +} diff --git a/internal/dao/admins.go b/internal/dao/admins.go new file mode 100644 index 0000000..d741e91 --- /dev/null +++ b/internal/dao/admins.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "server/internal/dao/internal" +) + +// internalAdminsDao is an internal type for wrapping the internal DAO implementation. +type internalAdminsDao = *internal.AdminsDao + +// adminsDao is the data access object for the table admins. +// You can define custom methods on it to extend its functionality as needed. +type adminsDao struct { + internalAdminsDao +} + +var ( + // Admins is a globally accessible object for table admins operations. + Admins = adminsDao{ + internal.NewAdminsDao(), + } +) + +// Add your custom methods and functionality below. diff --git a/internal/dao/authors.go b/internal/dao/authors.go new file mode 100644 index 0000000..b5a72df --- /dev/null +++ b/internal/dao/authors.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "server/internal/dao/internal" +) + +// internalAuthorsDao is an internal type for wrapping the internal DAO implementation. +type internalAuthorsDao = *internal.AuthorsDao + +// authorsDao is the data access object for the table authors. +// You can define custom methods on it to extend its functionality as needed. +type authorsDao struct { + internalAuthorsDao +} + +var ( + // Authors is a globally accessible object for table authors operations. + Authors = authorsDao{ + internal.NewAuthorsDao(), + } +) + +// Add your custom methods and functionality below. diff --git a/internal/dao/book_ratings.go b/internal/dao/book_ratings.go new file mode 100644 index 0000000..41aef42 --- /dev/null +++ b/internal/dao/book_ratings.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "server/internal/dao/internal" +) + +// internalBookRatingsDao is an internal type for wrapping the internal DAO implementation. +type internalBookRatingsDao = *internal.BookRatingsDao + +// bookRatingsDao is the data access object for the table book_ratings. +// You can define custom methods on it to extend its functionality as needed. +type bookRatingsDao struct { + internalBookRatingsDao +} + +var ( + // BookRatings is a globally accessible object for table book_ratings operations. + BookRatings = bookRatingsDao{ + internal.NewBookRatingsDao(), + } +) + +// Add your custom methods and functionality below. diff --git a/internal/dao/books.go b/internal/dao/books.go new file mode 100644 index 0000000..e9e7a4d --- /dev/null +++ b/internal/dao/books.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "server/internal/dao/internal" +) + +// internalBooksDao is an internal type for wrapping the internal DAO implementation. +type internalBooksDao = *internal.BooksDao + +// booksDao is the data access object for the table books. +// You can define custom methods on it to extend its functionality as needed. +type booksDao struct { + internalBooksDao +} + +var ( + // Books is a globally accessible object for table books operations. + Books = booksDao{ + internal.NewBooksDao(), + } +) + +// Add your custom methods and functionality below. diff --git a/internal/dao/bookshelves.go b/internal/dao/bookshelves.go new file mode 100644 index 0000000..8b13cd1 --- /dev/null +++ b/internal/dao/bookshelves.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "server/internal/dao/internal" +) + +// internalBookshelvesDao is an internal type for wrapping the internal DAO implementation. +type internalBookshelvesDao = *internal.BookshelvesDao + +// bookshelvesDao is the data access object for the table bookshelves. +// You can define custom methods on it to extend its functionality as needed. +type bookshelvesDao struct { + internalBookshelvesDao +} + +var ( + // Bookshelves is a globally accessible object for table bookshelves operations. + Bookshelves = bookshelvesDao{ + internal.NewBookshelvesDao(), + } +) + +// Add your custom methods and functionality below. diff --git a/internal/dao/categories.go b/internal/dao/categories.go new file mode 100644 index 0000000..6c1f473 --- /dev/null +++ b/internal/dao/categories.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "server/internal/dao/internal" +) + +// internalCategoriesDao is an internal type for wrapping the internal DAO implementation. +type internalCategoriesDao = *internal.CategoriesDao + +// categoriesDao is the data access object for the table categories. +// You can define custom methods on it to extend its functionality as needed. +type categoriesDao struct { + internalCategoriesDao +} + +var ( + // Categories is a globally accessible object for table categories operations. + Categories = categoriesDao{ + internal.NewCategoriesDao(), + } +) + +// Add your custom methods and functionality below. diff --git a/internal/dao/chapters.go b/internal/dao/chapters.go new file mode 100644 index 0000000..c1180f3 --- /dev/null +++ b/internal/dao/chapters.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "server/internal/dao/internal" +) + +// internalChaptersDao is an internal type for wrapping the internal DAO implementation. +type internalChaptersDao = *internal.ChaptersDao + +// chaptersDao is the data access object for the table chapters. +// You can define custom methods on it to extend its functionality as needed. +type chaptersDao struct { + internalChaptersDao +} + +var ( + // Chapters is a globally accessible object for table chapters operations. + Chapters = chaptersDao{ + internal.NewChaptersDao(), + } +) + +// Add your custom methods and functionality below. diff --git a/internal/dao/feedbacks.go b/internal/dao/feedbacks.go new file mode 100644 index 0000000..2938821 --- /dev/null +++ b/internal/dao/feedbacks.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "server/internal/dao/internal" +) + +// internalFeedbacksDao is an internal type for wrapping the internal DAO implementation. +type internalFeedbacksDao = *internal.FeedbacksDao + +// feedbacksDao is the data access object for the table feedbacks. +// You can define custom methods on it to extend its functionality as needed. +type feedbacksDao struct { + internalFeedbacksDao +} + +var ( + // Feedbacks is a globally accessible object for table feedbacks operations. + Feedbacks = feedbacksDao{ + internal.NewFeedbacksDao(), + } +) + +// Add your custom methods and functionality below. diff --git a/internal/dao/internal/admins.go b/internal/dao/internal/admins.go new file mode 100644 index 0000000..36ac685 --- /dev/null +++ b/internal/dao/internal/admins.go @@ -0,0 +1,83 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// AdminsDao is the data access object for the table admins. +type AdminsDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns AdminsColumns // columns contains all the column names of Table for convenient usage. +} + +// AdminsColumns defines and stores column names for the table admins. +type AdminsColumns struct { + Id string // 管理员ID + Username string // 管理员用户名 + PasswordHash string // 密码哈希 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 + DeletedAt string // 软删除时间戳 +} + +// adminsColumns holds the columns for the table admins. +var adminsColumns = AdminsColumns{ + Id: "id", + Username: "username", + PasswordHash: "password_hash", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", +} + +// NewAdminsDao creates and returns a new DAO object for table data access. +func NewAdminsDao() *AdminsDao { + return &AdminsDao{ + group: "default", + table: "admins", + columns: adminsColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *AdminsDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *AdminsDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *AdminsDao) Columns() AdminsColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *AdminsDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *AdminsDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *AdminsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/authors.go b/internal/dao/internal/authors.go new file mode 100644 index 0000000..b55e089 --- /dev/null +++ b/internal/dao/internal/authors.go @@ -0,0 +1,87 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// AuthorsDao is the data access object for the table authors. +type AuthorsDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns AuthorsColumns // columns contains all the column names of Table for convenient usage. +} + +// AuthorsColumns defines and stores column names for the table authors. +type AuthorsColumns struct { + Id string // 作者ID + UserId string // 用户ID + PenName string // 笔名 + Bio string // 作者简介 + Status string // 状态:1=正常,2=禁用 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 + DeletedAt string // 软删除时间戳 +} + +// authorsColumns holds the columns for the table authors. +var authorsColumns = AuthorsColumns{ + Id: "id", + UserId: "user_id", + PenName: "pen_name", + Bio: "bio", + Status: "status", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", +} + +// NewAuthorsDao creates and returns a new DAO object for table data access. +func NewAuthorsDao() *AuthorsDao { + return &AuthorsDao{ + group: "default", + table: "authors", + columns: authorsColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *AuthorsDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *AuthorsDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *AuthorsDao) Columns() AuthorsColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *AuthorsDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *AuthorsDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *AuthorsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/book_ratings.go b/internal/dao/internal/book_ratings.go new file mode 100644 index 0000000..40ca7a0 --- /dev/null +++ b/internal/dao/internal/book_ratings.go @@ -0,0 +1,83 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// BookRatingsDao is the data access object for the table book_ratings. +type BookRatingsDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns BookRatingsColumns // columns contains all the column names of Table for convenient usage. +} + +// BookRatingsColumns defines and stores column names for the table book_ratings. +type BookRatingsColumns struct { + Id string // 评分ID + UserId string // 用户ID + BookId string // 小说ID + Score string // 评分(0~10) + Comment string // 用户评论 + CreatedAt string // 创建时间 +} + +// bookRatingsColumns holds the columns for the table book_ratings. +var bookRatingsColumns = BookRatingsColumns{ + Id: "id", + UserId: "user_id", + BookId: "book_id", + Score: "score", + Comment: "comment", + CreatedAt: "created_at", +} + +// NewBookRatingsDao creates and returns a new DAO object for table data access. +func NewBookRatingsDao() *BookRatingsDao { + return &BookRatingsDao{ + group: "default", + table: "book_ratings", + columns: bookRatingsColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *BookRatingsDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *BookRatingsDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *BookRatingsDao) Columns() BookRatingsColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *BookRatingsDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *BookRatingsDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *BookRatingsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/books.go b/internal/dao/internal/books.go new file mode 100644 index 0000000..6fed503 --- /dev/null +++ b/internal/dao/internal/books.go @@ -0,0 +1,105 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// BooksDao is the data access object for the table books. +type BooksDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns BooksColumns // columns contains all the column names of Table for convenient usage. +} + +// BooksColumns defines and stores column names for the table books. +type BooksColumns struct { + Id string // 小说ID + AuthorId string // 作者ID + CategoryId string // 分类ID + Title string // 小说标题 + CoverUrl string // 封面图片URL + Description string // 小说简介 + Status string // 状态:1=连载中,2=完结,3=下架 + WordsCount string // 字数 + ChaptersCount string // 章节数 + LatestChapterId string // 最新章节ID + Rating string // 评分(0.00~10.00) + ReadCount string // 阅读人数 + Tags string // 标签(逗号分隔) + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 + DeletedAt string // 软删除时间戳 + IsRecommended string // 是否推荐:0=否,1=是 +} + +// booksColumns holds the columns for the table books. +var booksColumns = BooksColumns{ + Id: "id", + AuthorId: "author_id", + CategoryId: "category_id", + Title: "title", + CoverUrl: "cover_url", + Description: "description", + Status: "status", + WordsCount: "words_count", + ChaptersCount: "chapters_count", + LatestChapterId: "latest_chapter_id", + Rating: "rating", + ReadCount: "read_count", + Tags: "tags", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", + IsRecommended: "is_recommended", +} + +// NewBooksDao creates and returns a new DAO object for table data access. +func NewBooksDao() *BooksDao { + return &BooksDao{ + group: "default", + table: "books", + columns: booksColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *BooksDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *BooksDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *BooksDao) Columns() BooksColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *BooksDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *BooksDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *BooksDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/bookshelves.go b/internal/dao/internal/bookshelves.go new file mode 100644 index 0000000..237c2f5 --- /dev/null +++ b/internal/dao/internal/bookshelves.go @@ -0,0 +1,85 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// BookshelvesDao is the data access object for the table bookshelves. +type BookshelvesDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns BookshelvesColumns // columns contains all the column names of Table for convenient usage. +} + +// BookshelvesColumns defines and stores column names for the table bookshelves. +type BookshelvesColumns struct { + Id string // 记录ID + UserId string // 用户ID + BookId string // 小说ID + AddedAt string // 加入书架时间 + LastReadChapterId string // 最后阅读章节ID + LastReadPercent string // 阅读进度百分比(0.00~100.00) + LastReadAt string // 最后阅读时间 +} + +// bookshelvesColumns holds the columns for the table bookshelves. +var bookshelvesColumns = BookshelvesColumns{ + Id: "id", + UserId: "user_id", + BookId: "book_id", + AddedAt: "added_at", + LastReadChapterId: "last_read_chapter_id", + LastReadPercent: "last_read_percent", + LastReadAt: "last_read_at", +} + +// NewBookshelvesDao creates and returns a new DAO object for table data access. +func NewBookshelvesDao() *BookshelvesDao { + return &BookshelvesDao{ + group: "default", + table: "bookshelves", + columns: bookshelvesColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *BookshelvesDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *BookshelvesDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *BookshelvesDao) Columns() BookshelvesColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *BookshelvesDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *BookshelvesDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *BookshelvesDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/categories.go b/internal/dao/internal/categories.go new file mode 100644 index 0000000..1760a15 --- /dev/null +++ b/internal/dao/internal/categories.go @@ -0,0 +1,83 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// CategoriesDao is the data access object for the table categories. +type CategoriesDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns CategoriesColumns // columns contains all the column names of Table for convenient usage. +} + +// CategoriesColumns defines and stores column names for the table categories. +type CategoriesColumns struct { + Id string // 分类ID + Name string // 分类名称 + Type string // 分类类型:1=男频, 2=女频 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 + DeletedAt string // 软删除时间戳 +} + +// categoriesColumns holds the columns for the table categories. +var categoriesColumns = CategoriesColumns{ + Id: "id", + Name: "name", + Type: "type", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", +} + +// NewCategoriesDao creates and returns a new DAO object for table data access. +func NewCategoriesDao() *CategoriesDao { + return &CategoriesDao{ + group: "default", + table: "categories", + columns: categoriesColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *CategoriesDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *CategoriesDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *CategoriesDao) Columns() CategoriesColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *CategoriesDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *CategoriesDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *CategoriesDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/chapters.go b/internal/dao/internal/chapters.go new file mode 100644 index 0000000..32541cb --- /dev/null +++ b/internal/dao/internal/chapters.go @@ -0,0 +1,93 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// ChaptersDao is the data access object for the table chapters. +type ChaptersDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns ChaptersColumns // columns contains all the column names of Table for convenient usage. +} + +// ChaptersColumns defines and stores column names for the table chapters. +type ChaptersColumns struct { + Id string // 章节ID + BookId string // 小说ID + Title string // 章节标题 + Content string // 章节内容 + WordCount string // 章节字数 + Sort string // 排序序号 + IsLocked string // 是否锁定:0=免费,1=需积分解锁 + RequiredScore string // 解锁该章节所需积分 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 + DeletedAt string // 软删除时间戳 +} + +// chaptersColumns holds the columns for the table chapters. +var chaptersColumns = ChaptersColumns{ + Id: "id", + BookId: "book_id", + Title: "title", + Content: "content", + WordCount: "word_count", + Sort: "sort", + IsLocked: "is_locked", + RequiredScore: "required_score", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", +} + +// NewChaptersDao creates and returns a new DAO object for table data access. +func NewChaptersDao() *ChaptersDao { + return &ChaptersDao{ + group: "default", + table: "chapters", + columns: chaptersColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *ChaptersDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *ChaptersDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *ChaptersDao) Columns() ChaptersColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *ChaptersDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *ChaptersDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *ChaptersDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/feedbacks.go b/internal/dao/internal/feedbacks.go new file mode 100644 index 0000000..e0390be --- /dev/null +++ b/internal/dao/internal/feedbacks.go @@ -0,0 +1,83 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// FeedbacksDao is the data access object for the table feedbacks. +type FeedbacksDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns FeedbacksColumns // columns contains all the column names of Table for convenient usage. +} + +// FeedbacksColumns defines and stores column names for the table feedbacks. +type FeedbacksColumns struct { + Id string // 反馈ID + UserId string // 用户ID + Content string // 反馈内容 + Status string // 处理状态:1=未处理,2=处理中,3=已处理 + CreatedAt string // 反馈时间 + UpdatedAt string // 更新时间 +} + +// feedbacksColumns holds the columns for the table feedbacks. +var feedbacksColumns = FeedbacksColumns{ + Id: "id", + UserId: "user_id", + Content: "content", + Status: "status", + CreatedAt: "created_at", + UpdatedAt: "updated_at", +} + +// NewFeedbacksDao creates and returns a new DAO object for table data access. +func NewFeedbacksDao() *FeedbacksDao { + return &FeedbacksDao{ + group: "default", + table: "feedbacks", + columns: feedbacksColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *FeedbacksDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *FeedbacksDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *FeedbacksDao) Columns() FeedbacksColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *FeedbacksDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *FeedbacksDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *FeedbacksDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/read_records.go b/internal/dao/internal/read_records.go new file mode 100644 index 0000000..226bf0e --- /dev/null +++ b/internal/dao/internal/read_records.go @@ -0,0 +1,81 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// ReadRecordsDao is the data access object for the table read_records. +type ReadRecordsDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns ReadRecordsColumns // columns contains all the column names of Table for convenient usage. +} + +// ReadRecordsColumns defines and stores column names for the table read_records. +type ReadRecordsColumns struct { + Id string // 记录ID + UserId string // 用户ID + BookId string // 小说ID + ChapterId string // 章节ID + ReadAt string // 阅读时间 +} + +// readRecordsColumns holds the columns for the table read_records. +var readRecordsColumns = ReadRecordsColumns{ + Id: "id", + UserId: "user_id", + BookId: "book_id", + ChapterId: "chapter_id", + ReadAt: "read_at", +} + +// NewReadRecordsDao creates and returns a new DAO object for table data access. +func NewReadRecordsDao() *ReadRecordsDao { + return &ReadRecordsDao{ + group: "default", + table: "read_records", + columns: readRecordsColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *ReadRecordsDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *ReadRecordsDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *ReadRecordsDao) Columns() ReadRecordsColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *ReadRecordsDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *ReadRecordsDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *ReadRecordsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/tags.go b/internal/dao/internal/tags.go new file mode 100644 index 0000000..dd11fee --- /dev/null +++ b/internal/dao/internal/tags.go @@ -0,0 +1,83 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// TagsDao is the data access object for the table tags. +type TagsDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns TagsColumns // columns contains all the column names of Table for convenient usage. +} + +// TagsColumns defines and stores column names for the table tags. +type TagsColumns struct { + Id string // 标签ID + Name string // 标签名称 + Type string // 标签类型:1=主题, 2=角色, 3=情节 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 + DeletedAt string // 软删除时间戳 +} + +// tagsColumns holds the columns for the table tags. +var tagsColumns = TagsColumns{ + Id: "id", + Name: "name", + Type: "type", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", +} + +// NewTagsDao creates and returns a new DAO object for table data access. +func NewTagsDao() *TagsDao { + return &TagsDao{ + group: "default", + table: "tags", + columns: tagsColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *TagsDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *TagsDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *TagsDao) Columns() TagsColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *TagsDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *TagsDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *TagsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/user_chapter_purchases.go b/internal/dao/internal/user_chapter_purchases.go new file mode 100644 index 0000000..9ee4f34 --- /dev/null +++ b/internal/dao/internal/user_chapter_purchases.go @@ -0,0 +1,83 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// UserChapterPurchasesDao is the data access object for the table user_chapter_purchases. +type UserChapterPurchasesDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns UserChapterPurchasesColumns // columns contains all the column names of Table for convenient usage. +} + +// UserChapterPurchasesColumns defines and stores column names for the table user_chapter_purchases. +type UserChapterPurchasesColumns struct { + Id string // 购买记录ID + UserId string // 用户ID + BookId string // 小说ID + ChapterId string // 章节ID + PointsUsed string // 消耗积分数 + PurchaseTime string // 购买时间 +} + +// userChapterPurchasesColumns holds the columns for the table user_chapter_purchases. +var userChapterPurchasesColumns = UserChapterPurchasesColumns{ + Id: "id", + UserId: "user_id", + BookId: "book_id", + ChapterId: "chapter_id", + PointsUsed: "points_used", + PurchaseTime: "purchase_time", +} + +// NewUserChapterPurchasesDao creates and returns a new DAO object for table data access. +func NewUserChapterPurchasesDao() *UserChapterPurchasesDao { + return &UserChapterPurchasesDao{ + group: "default", + table: "user_chapter_purchases", + columns: userChapterPurchasesColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *UserChapterPurchasesDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *UserChapterPurchasesDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *UserChapterPurchasesDao) Columns() UserChapterPurchasesColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *UserChapterPurchasesDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *UserChapterPurchasesDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *UserChapterPurchasesDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/user_follow_authors.go b/internal/dao/internal/user_follow_authors.go new file mode 100644 index 0000000..477804e --- /dev/null +++ b/internal/dao/internal/user_follow_authors.go @@ -0,0 +1,79 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// UserFollowAuthorsDao is the data access object for the table user_follow_authors. +type UserFollowAuthorsDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns UserFollowAuthorsColumns // columns contains all the column names of Table for convenient usage. +} + +// UserFollowAuthorsColumns defines and stores column names for the table user_follow_authors. +type UserFollowAuthorsColumns struct { + Id string // 关注ID + UserId string // 用户ID + AuthorId string // 作者ID + FollowedAt string // 关注时间 +} + +// userFollowAuthorsColumns holds the columns for the table user_follow_authors. +var userFollowAuthorsColumns = UserFollowAuthorsColumns{ + Id: "id", + UserId: "user_id", + AuthorId: "author_id", + FollowedAt: "followed_at", +} + +// NewUserFollowAuthorsDao creates and returns a new DAO object for table data access. +func NewUserFollowAuthorsDao() *UserFollowAuthorsDao { + return &UserFollowAuthorsDao{ + group: "default", + table: "user_follow_authors", + columns: userFollowAuthorsColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *UserFollowAuthorsDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *UserFollowAuthorsDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *UserFollowAuthorsDao) Columns() UserFollowAuthorsColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *UserFollowAuthorsDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *UserFollowAuthorsDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *UserFollowAuthorsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/user_points.go b/internal/dao/internal/user_points.go new file mode 100644 index 0000000..9a8f37b --- /dev/null +++ b/internal/dao/internal/user_points.go @@ -0,0 +1,79 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// UserPointsDao is the data access object for the table user_points. +type UserPointsDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns UserPointsColumns // columns contains all the column names of Table for convenient usage. +} + +// UserPointsColumns defines and stores column names for the table user_points. +type UserPointsColumns struct { + Id string // 积分账户ID + UserId string // 用户ID + PointsBalance string // 当前积分余额 + UpdatedAt string // 更新时间 +} + +// userPointsColumns holds the columns for the table user_points. +var userPointsColumns = UserPointsColumns{ + Id: "id", + UserId: "user_id", + PointsBalance: "points_balance", + UpdatedAt: "updated_at", +} + +// NewUserPointsDao creates and returns a new DAO object for table data access. +func NewUserPointsDao() *UserPointsDao { + return &UserPointsDao{ + group: "default", + table: "user_points", + columns: userPointsColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *UserPointsDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *UserPointsDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *UserPointsDao) Columns() UserPointsColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *UserPointsDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *UserPointsDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *UserPointsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/user_points_logs.go b/internal/dao/internal/user_points_logs.go new file mode 100644 index 0000000..e261c5d --- /dev/null +++ b/internal/dao/internal/user_points_logs.go @@ -0,0 +1,85 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// UserPointsLogsDao is the data access object for the table user_points_logs. +type UserPointsLogsDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns UserPointsLogsColumns // columns contains all the column names of Table for convenient usage. +} + +// UserPointsLogsColumns defines and stores column names for the table user_points_logs. +type UserPointsLogsColumns struct { + Id string // 积分流水ID + UserId string // 用户ID + ChangeType string // 变动类型,例如 earn、spend、refund 等 + PointsChange string // 积分变化数,正数增加,负数减少 + RelatedOrderId string // 关联订单ID + Description string // 变动说明 + CreatedAt string // 变动时间 +} + +// userPointsLogsColumns holds the columns for the table user_points_logs. +var userPointsLogsColumns = UserPointsLogsColumns{ + Id: "id", + UserId: "user_id", + ChangeType: "change_type", + PointsChange: "points_change", + RelatedOrderId: "related_order_id", + Description: "description", + CreatedAt: "created_at", +} + +// NewUserPointsLogsDao creates and returns a new DAO object for table data access. +func NewUserPointsLogsDao() *UserPointsLogsDao { + return &UserPointsLogsDao{ + group: "default", + table: "user_points_logs", + columns: userPointsLogsColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *UserPointsLogsDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *UserPointsLogsDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *UserPointsLogsDao) Columns() UserPointsLogsColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *UserPointsLogsDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *UserPointsLogsDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *UserPointsLogsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/users.go b/internal/dao/internal/users.go new file mode 100644 index 0000000..41ab041 --- /dev/null +++ b/internal/dao/internal/users.go @@ -0,0 +1,89 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// UsersDao is the data access object for the table users. +type UsersDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of the current DAO. + columns UsersColumns // columns contains all the column names of Table for convenient usage. +} + +// UsersColumns defines and stores column names for the table users. +type UsersColumns struct { + Id string // 用户ID + Username string // 用户名 + PasswordHash string // 密码哈希 + Avatar string // 头像URL + Email string // 邮箱 + Points string // 积分 + CreatedAt string // 注册时间 + UpdatedAt string // 更新时间 + DeletedAt string // 软删除时间戳 +} + +// usersColumns holds the columns for the table users. +var usersColumns = UsersColumns{ + Id: "id", + Username: "username", + PasswordHash: "password_hash", + Avatar: "avatar", + Email: "email", + Points: "points", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", +} + +// NewUsersDao creates and returns a new DAO object for table data access. +func NewUsersDao() *UsersDao { + return &UsersDao{ + group: "default", + table: "users", + columns: usersColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of the current DAO. +func (dao *UsersDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of the current DAO. +func (dao *UsersDao) Table() string { + return dao.table +} + +// Columns returns all column names of the current DAO. +func (dao *UsersDao) Columns() UsersColumns { + return dao.columns +} + +// Group returns the database configuration group name of the current DAO. +func (dao *UsersDao) Group() string { + return dao.group +} + +// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation. +func (dao *UsersDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rolls back the transaction and returns the error if function f returns a non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note: Do not commit or roll back the transaction in function f, +// as it is automatically handled by this function. +func (dao *UsersDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/read_records.go b/internal/dao/read_records.go new file mode 100644 index 0000000..bd38228 --- /dev/null +++ b/internal/dao/read_records.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "server/internal/dao/internal" +) + +// internalReadRecordsDao is an internal type for wrapping the internal DAO implementation. +type internalReadRecordsDao = *internal.ReadRecordsDao + +// readRecordsDao is the data access object for the table read_records. +// You can define custom methods on it to extend its functionality as needed. +type readRecordsDao struct { + internalReadRecordsDao +} + +var ( + // ReadRecords is a globally accessible object for table read_records operations. + ReadRecords = readRecordsDao{ + internal.NewReadRecordsDao(), + } +) + +// Add your custom methods and functionality below. diff --git a/internal/dao/tags.go b/internal/dao/tags.go new file mode 100644 index 0000000..bda89e2 --- /dev/null +++ b/internal/dao/tags.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "server/internal/dao/internal" +) + +// internalTagsDao is an internal type for wrapping the internal DAO implementation. +type internalTagsDao = *internal.TagsDao + +// tagsDao is the data access object for the table tags. +// You can define custom methods on it to extend its functionality as needed. +type tagsDao struct { + internalTagsDao +} + +var ( + // Tags is a globally accessible object for table tags operations. + Tags = tagsDao{ + internal.NewTagsDao(), + } +) + +// Add your custom methods and functionality below. diff --git a/internal/dao/user_chapter_purchases.go b/internal/dao/user_chapter_purchases.go new file mode 100644 index 0000000..519239f --- /dev/null +++ b/internal/dao/user_chapter_purchases.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "server/internal/dao/internal" +) + +// internalUserChapterPurchasesDao is an internal type for wrapping the internal DAO implementation. +type internalUserChapterPurchasesDao = *internal.UserChapterPurchasesDao + +// userChapterPurchasesDao is the data access object for the table user_chapter_purchases. +// You can define custom methods on it to extend its functionality as needed. +type userChapterPurchasesDao struct { + internalUserChapterPurchasesDao +} + +var ( + // UserChapterPurchases is a globally accessible object for table user_chapter_purchases operations. + UserChapterPurchases = userChapterPurchasesDao{ + internal.NewUserChapterPurchasesDao(), + } +) + +// Add your custom methods and functionality below. diff --git a/internal/dao/user_follow_authors.go b/internal/dao/user_follow_authors.go new file mode 100644 index 0000000..f30a078 --- /dev/null +++ b/internal/dao/user_follow_authors.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "server/internal/dao/internal" +) + +// internalUserFollowAuthorsDao is an internal type for wrapping the internal DAO implementation. +type internalUserFollowAuthorsDao = *internal.UserFollowAuthorsDao + +// userFollowAuthorsDao is the data access object for the table user_follow_authors. +// You can define custom methods on it to extend its functionality as needed. +type userFollowAuthorsDao struct { + internalUserFollowAuthorsDao +} + +var ( + // UserFollowAuthors is a globally accessible object for table user_follow_authors operations. + UserFollowAuthors = userFollowAuthorsDao{ + internal.NewUserFollowAuthorsDao(), + } +) + +// Add your custom methods and functionality below. diff --git a/internal/dao/user_points.go b/internal/dao/user_points.go new file mode 100644 index 0000000..94650b0 --- /dev/null +++ b/internal/dao/user_points.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "server/internal/dao/internal" +) + +// internalUserPointsDao is an internal type for wrapping the internal DAO implementation. +type internalUserPointsDao = *internal.UserPointsDao + +// userPointsDao is the data access object for the table user_points. +// You can define custom methods on it to extend its functionality as needed. +type userPointsDao struct { + internalUserPointsDao +} + +var ( + // UserPoints is a globally accessible object for table user_points operations. + UserPoints = userPointsDao{ + internal.NewUserPointsDao(), + } +) + +// Add your custom methods and functionality below. diff --git a/internal/dao/user_points_logs.go b/internal/dao/user_points_logs.go new file mode 100644 index 0000000..4c1a766 --- /dev/null +++ b/internal/dao/user_points_logs.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "server/internal/dao/internal" +) + +// internalUserPointsLogsDao is an internal type for wrapping the internal DAO implementation. +type internalUserPointsLogsDao = *internal.UserPointsLogsDao + +// userPointsLogsDao is the data access object for the table user_points_logs. +// You can define custom methods on it to extend its functionality as needed. +type userPointsLogsDao struct { + internalUserPointsLogsDao +} + +var ( + // UserPointsLogs is a globally accessible object for table user_points_logs operations. + UserPointsLogs = userPointsLogsDao{ + internal.NewUserPointsLogsDao(), + } +) + +// Add your custom methods and functionality below. diff --git a/internal/dao/users.go b/internal/dao/users.go new file mode 100644 index 0000000..a7a7d3e --- /dev/null +++ b/internal/dao/users.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed. +// ================================================================================= + +package dao + +import ( + "server/internal/dao/internal" +) + +// internalUsersDao is an internal type for wrapping the internal DAO implementation. +type internalUsersDao = *internal.UsersDao + +// usersDao is the data access object for the table users. +// You can define custom methods on it to extend its functionality as needed. +type usersDao struct { + internalUsersDao +} + +var ( + // Users is a globally accessible object for table users operations. + Users = usersDao{ + internal.NewUsersDao(), + } +) + +// Add your custom methods and functionality below. diff --git a/internal/logic/admin/admin.go b/internal/logic/admin/admin.go new file mode 100644 index 0000000..6ea13eb --- /dev/null +++ b/internal/logic/admin/admin.go @@ -0,0 +1,92 @@ +package admin + +import ( + "context" + "server/internal/consts" + "server/internal/dao" + "server/internal/model" + "server/internal/model/do" + "server/internal/model/entity" + "server/internal/service" + "server/utility/ecode" + "server/utility/encrypt" + "server/utility/jwt" +) + +type sAdmin struct{} + +func init() { + service.RegisterAdmin(New()) +} + +func New() service.IAdmin { + return &sAdmin{} +} + +func (s *sAdmin) Login(ctx context.Context, in *model.AdminLoginIn) (out *model.AdminLoginOut, err error) { + admin, err := dao.Admins.Ctx(ctx).Where(dao.Admins.Columns().Username, in.Username).One() + if err != nil { + return nil, ecode.Fail.Sub("database_query_failed") + } + + if admin.IsEmpty() { + return nil, ecode.Auth + } + + if !encrypt.ComparePassword(admin[dao.Admins.Columns().PasswordHash].String(), in.Password) { + return nil, ecode.Password + } + token, err := jwt.GenerateToken(&jwt.TokenIn{ + Role: consts.AdminRoleCode, + UserId: admin[dao.Admins.Columns().Id].Int64(), + }) + if err != nil { + return nil, ecode.Fail.Sub("token_generation_failed") + } + return &model.AdminLoginOut{ + Token: token, + }, nil +} + +func (s *sAdmin) Info(ctx context.Context, in *model.AdminInfoIn) (out *model.AdminInfoOut, err error) { + exist, err := dao.Admins.Ctx(ctx).WherePri(in.AdminId).Exist() + if err != nil { + return nil, ecode.Fail.Sub("admin_query_failed") + } + if !exist { + return nil, ecode.Auth.Sub("admin_not_found") + } + var admin entity.Admins + err = dao.Admins.Ctx(ctx).WherePri(in.AdminId).Scan(&admin) + if err != nil { + return nil, ecode.Fail.Sub("admin_query_failed") + } + return &model.AdminInfoOut{ + AdminId: admin.Id, + Username: admin.Username, + }, nil +} + +func (s *sAdmin) EditPass(ctx context.Context, in *model.AdminEditPassIn) (out *model.AdminEditPassOut, err error) { + admin, err := dao.Admins.Ctx(ctx).WherePri(in.AdminId).One() + if err != nil { + return nil, ecode.Fail.Sub("admin_query_failed") + } + if admin.IsEmpty() { + return nil, ecode.Auth.Sub("admin_not_found") + } + if !encrypt.ComparePassword(admin[dao.Admins.Columns().PasswordHash].String(), in.OldPass) { + return nil, ecode.Password.Sub("password_incorrect") + } + hash, err := encrypt.EncryptPassword(in.NewPass) + if err != nil { + return nil, ecode.Fail.Sub("password_encryption_failed") + } + _, err = dao.Admins.Ctx(ctx).WherePri(in.AdminId).Data(do.Admins{PasswordHash: hash}).Update() + if err != nil { + return nil, ecode.Fail.Sub("password_update_failed") + } + return &model.AdminEditPassOut{ + Success: true, + }, nil +} diff --git a/internal/logic/book/book.go b/internal/logic/book/book.go new file mode 100644 index 0000000..4cf6771 --- /dev/null +++ b/internal/logic/book/book.go @@ -0,0 +1,138 @@ +package book + +import ( + "context" + "server/internal/dao" + "server/internal/model" + "server/internal/model/do" + "server/internal/service" + "server/utility/ecode" +) + +type sBook struct{} + +func New() service.IBook { + return &sBook{} +} + +func init() { + service.RegisterBook(New()) +} + +// List retrieves a paginated list of books +func (s *sBook) List(ctx context.Context, in *model.BookListIn) (out *model.BookListOut, err error) { + out = &model.BookListOut{} + m := dao.Books.Ctx(ctx) + if in.Title != "" { + m = m.Where(dao.Books.Columns().Title+" like ?", "%"+in.Title+"%") + } + if in.CategoryId != 0 { + m = m.Where(dao.Books.Columns().CategoryId, in.CategoryId) + } + if in.AuthorId != 0 { + m = m.Where(dao.Books.Columns().AuthorId, in.AuthorId) + } + if in.Status != 0 { + m = m.Where(dao.Books.Columns().Status, in.Status) + } + if in.IsRecommended != 0 { + m = m.Where(dao.Books.Columns().IsRecommended, in.IsRecommended) + } + if err = m.Page(in.Page, in.Size).ScanAndCount(&out.List, &out.Total, false); err != nil { + return + } + return +} + +func (s *sBook) Create(ctx context.Context, in *model.BookAddIn) (out *model.BookCRUDOut, err error) { + exist, err := dao.Books.Ctx(ctx). + Where(dao.Books.Columns().Title, in.Title). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("book_query_failed") + } + if exist { + return nil, ecode.Params.Sub("book_exists") + } + + if _, err := dao.Books.Ctx(ctx).Data(do.Books{ + AuthorId: in.AuthorId, + CategoryId: in.CategoryId, + Title: in.Title, + CoverUrl: in.CoverUrl, + Description: in.Description, + Status: in.Status, + Tags: in.Tags, + IsRecommended: in.IsRecommended, + }).Insert(); err != nil { + return nil, ecode.Fail.Sub("book_create_failed") + } + + return &model.BookCRUDOut{ + Success: true, + }, nil +} + +func (s *sBook) Update(ctx context.Context, in *model.BookEditIn) (out *model.BookCRUDOut, err error) { + exist, err := dao.Books.Ctx(ctx). + WherePri(in.Id). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("book_query_failed") + } + if !exist { + return nil, ecode.NotFound.Sub("book_not_found") + } + + exist, err = dao.Books.Ctx(ctx). + Where(dao.Books.Columns().Title, in.Title). + Where("id != ?", in.Id). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("book_query_failed") + } + if exist { + return nil, ecode.Params.Sub("book_exists") + } + + _, err = dao.Books.Ctx(ctx). + WherePri(in.Id). + Data(do.Books{ + AuthorId: in.AuthorId, + CategoryId: in.CategoryId, + Title: in.Title, + CoverUrl: in.CoverUrl, + Description: in.Description, + Status: in.Status, + Tags: in.Tags, + IsRecommended: in.IsRecommended, + }).Update() + if err != nil { + return nil, ecode.Fail.Sub("book_update_failed") + } + + return &model.BookCRUDOut{ + Success: true, + }, nil +} + +func (s *sBook) Delete(ctx context.Context, in *model.BookDelIn) (out *model.BookCRUDOut, err error) { + exist, err := dao.Books.Ctx(ctx). + WherePri(in.Id). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("book_query_failed") + } + if !exist { + return nil, ecode.NotFound.Sub("book_not_found") + } + + _, err = dao.Books.Ctx(ctx).WherePri(in.Id).Delete() + if err != nil { + return nil, ecode.Fail.Sub("book_delete_failed") + } + + return &model.BookCRUDOut{ + Success: true, + }, nil +} diff --git a/internal/logic/category/category.go b/internal/logic/category/category.go new file mode 100644 index 0000000..b47835f --- /dev/null +++ b/internal/logic/category/category.go @@ -0,0 +1,123 @@ +package category + +import ( + "context" + "server/internal/dao" + "server/internal/model" + "server/internal/model/do" + "server/internal/service" + "server/utility/ecode" +) + +type sCategory struct { +} + +func New() service.ICategory { + return &sCategory{} +} + +func init() { + service.RegisterCategory(New()) +} + +// List retrieves a paginated list of categories +func (s *sCategory) List(ctx context.Context, in *model.CategoryListIn) (out *model.CategoryListOut, err error) { + out = &model.CategoryListOut{} + m := dao.Categories.Ctx(ctx) + if in.Type != 0 { + m = m.Where(dao.Categories.Columns().Type, in.Type) + } + if err = m.Page(in.Page, in.Size).ScanAndCount(&out.List, &out.Total, false); err != nil { + return + } + return +} + +func (s *sCategory) Create(ctx context.Context, in *model.CategoryAddIn) (out *model.CategoryCRUDOut, err error) { + if in.Type != 1 && in.Type != 2 { + return nil, ecode.Params.Sub("category_type_invalid") + } + exist, err := dao.Categories.Ctx(ctx). + Where(dao.Categories.Columns().Name, in.Name). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("category_query_failed") + } + if exist { + return nil, ecode.Params.Sub("category_exists") + } + + if _, err := dao.Categories.Ctx(ctx).Data(do.Categories{ + Name: in.Name, + Type: in.Type, + }).Insert(); err != nil { + return nil, ecode.Fail.Sub("category_create_failed") + } + + return &model.CategoryCRUDOut{ + Success: true, + }, nil +} + +func (s *sCategory) Update(ctx context.Context, in *model.CategoryEditIn) (out *model.CategoryCRUDOut, err error) { + if in.Type != 1 && in.Type != 2 { + return nil, ecode.Params.Sub("category_type_invalid") + } + exist, err := dao.Categories.Ctx(ctx). + WherePri(in.Id). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("category_query_failed") + } + if !exist { + return nil, ecode.NotFound.Sub("category_not_found") + } + + exist, err = dao.Categories.Ctx(ctx). + Where(dao.Categories.Columns().Name, in.Name). + Where("id != ?", in.Id). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("category_query_failed") + } + if exist { + return nil, ecode.Params.Sub("category_exists") + } + + // Update category + _, err = dao.Categories.Ctx(ctx). + WherePri(in.Id). + Data(do.Categories{ + Name: in.Name, + Type: in.Type, + }).Update() + if err != nil { + return nil, ecode.Fail.Sub("category_update_failed") + } + + return &model.CategoryCRUDOut{ + Success: true, + }, nil +} + +func (s *sCategory) Delete(ctx context.Context, in *model.CategoryDelIn) (out *model.CategoryCRUDOut, err error) { + exist, err := dao.Categories.Ctx(ctx). + WherePri(in.Id). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("category_query_failed") + } + if !exist { + return nil, ecode.NotFound.Sub("category_not_found") + } + + // Soft delete category + _, err = dao.Categories.Ctx(ctx).WherePri(in.Id).Delete() + if err != nil { + return nil, ecode.Fail.Sub("category_delete_failed") + } + + return &model.CategoryCRUDOut{ + Success: true, + }, nil +} diff --git a/internal/logic/chapter/chapter.go b/internal/logic/chapter/chapter.go new file mode 100644 index 0000000..cb2232f --- /dev/null +++ b/internal/logic/chapter/chapter.go @@ -0,0 +1,98 @@ +package chapter + +import ( + "context" + "server/internal/dao" + "server/internal/model" + "server/internal/model/do" + "server/internal/service" + "server/utility/ecode" +) + +type sChapter struct{} + +func New() service.IChapter { + return &sChapter{} +} + +func init() { + service.RegisterChapter(New()) +} + +// List retrieves a paginated list of chapters +func (s *sChapter) List(ctx context.Context, in *model.ChapterListIn) (out *model.ChapterListOut, err error) { + out = &model.ChapterListOut{} + m := dao.Chapters.Ctx(ctx) + if in.BookId != 0 { + m = m.Where(dao.Chapters.Columns().BookId, in.BookId) + } + if in.Title != "" { + m = m.Where(dao.Chapters.Columns().Title+" like ?", "%"+in.Title+"%") + } + if in.IsLocked != 0 { + m = m.Where(dao.Chapters.Columns().IsLocked, in.IsLocked) + } + if err = m.Page(in.Page, in.Size).ScanAndCount(&out.List, &out.Total, false); err != nil { + return + } + return +} + +func (s *sChapter) Create(ctx context.Context, in *model.ChapterAddIn) (out *model.ChapterCRUDOut, err error) { + if _, err := dao.Chapters.Ctx(ctx).Data(do.Chapters{ + BookId: in.BookId, + Title: in.Title, + Content: in.Content, + WordCount: in.WordCount, + Sort: in.Sort, + IsLocked: in.IsLocked, + RequiredScore: in.RequiredScore, + }).Insert(); err != nil { + return nil, ecode.Fail.Sub("chapter_create_failed") + } + return &model.ChapterCRUDOut{Success: true}, nil +} + +func (s *sChapter) Update(ctx context.Context, in *model.ChapterEditIn) (out *model.ChapterCRUDOut, err error) { + exist, err := dao.Chapters.Ctx(ctx). + WherePri(in.Id). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("chapter_query_failed") + } + if !exist { + return nil, ecode.NotFound.Sub("chapter_not_found") + } + _, err = dao.Chapters.Ctx(ctx). + WherePri(in.Id). + Data(do.Chapters{ + BookId: in.BookId, + Title: in.Title, + Content: in.Content, + WordCount: in.WordCount, + Sort: in.Sort, + IsLocked: in.IsLocked, + RequiredScore: in.RequiredScore, + }).Update() + if err != nil { + return nil, ecode.Fail.Sub("chapter_update_failed") + } + return &model.ChapterCRUDOut{Success: true}, nil +} + +func (s *sChapter) Delete(ctx context.Context, in *model.ChapterDelIn) (out *model.ChapterCRUDOut, err error) { + exist, err := dao.Chapters.Ctx(ctx). + WherePri(in.Id). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("chapter_query_failed") + } + if !exist { + return nil, ecode.NotFound.Sub("chapter_not_found") + } + _, err = dao.Chapters.Ctx(ctx).WherePri(in.Id).Delete() + if err != nil { + return nil, ecode.Fail.Sub("chapter_delete_failed") + } + return &model.ChapterCRUDOut{Success: true}, nil +} diff --git a/internal/logic/feedback/feedback.go b/internal/logic/feedback/feedback.go new file mode 100644 index 0000000..2f497c9 --- /dev/null +++ b/internal/logic/feedback/feedback.go @@ -0,0 +1,47 @@ +package feedback + +import ( + "context" + "server/internal/dao" + "server/internal/model" + "server/internal/model/do" + "server/internal/service" + "server/utility/ecode" +) + +type sFeedback struct{} + +func New() service.IFeedback { + return &sFeedback{} +} +func init() { + service.RegisterFeedback(New()) +} + +// List retrieves a paginated list of feedbacks +func (s *sFeedback) List(ctx context.Context, in *model.FeedbackListIn) (out *model.FeedbackListOut, err error) { + out = &model.FeedbackListOut{} + m := dao.Feedbacks.Ctx(ctx) + if in.UserId != 0 { + m = m.Where(dao.Feedbacks.Columns().UserId, in.UserId) + } + if in.Status != 0 { + m = m.Where(dao.Feedbacks.Columns().Status, in.Status) + } + if err = m.Page(in.Page, in.Size).ScanAndCount(&out.List, &out.Total, false); err != nil { + return + } + return +} + +// Create adds a new feedback +func (s *sFeedback) Create(ctx context.Context, in *model.FeedbackAddIn) (out *model.FeedbackCRUDOut, err error) { + if _, err := dao.Feedbacks.Ctx(ctx).Data(do.Feedbacks{ + UserId: in.UserId, + Content: in.Content, + Status: 1, // 默认未处理 + }).Insert(); err != nil { + return nil, ecode.Fail.Sub("feedback_create_failed") + } + return &model.FeedbackCRUDOut{Success: true}, nil +} diff --git a/internal/logic/logic.go b/internal/logic/logic.go new file mode 100644 index 0000000..781520c --- /dev/null +++ b/internal/logic/logic.go @@ -0,0 +1,16 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package logic + +import ( + _ "server/internal/logic/admin" + _ "server/internal/logic/book" + _ "server/internal/logic/category" + _ "server/internal/logic/chapter" + _ "server/internal/logic/feedback" + _ "server/internal/logic/read_record" + _ "server/internal/logic/tag" + _ "server/internal/logic/user" +) diff --git a/internal/logic/read_record/read_record.go b/internal/logic/read_record/read_record.go new file mode 100644 index 0000000..78479f1 --- /dev/null +++ b/internal/logic/read_record/read_record.go @@ -0,0 +1,68 @@ +package read_record + +import ( + "context" + "server/internal/dao" + "server/internal/model" + "server/internal/model/do" + "server/internal/service" + "server/utility/ecode" +) + +type sReadRecord struct{} + +func New() service.IReadRecord { + return &sReadRecord{} +} +func init() { + service.RegisterReadRecord(New()) +} + +// List retrieves a paginated list of read records +func (s *sReadRecord) List(ctx context.Context, in *model.ReadRecordListIn) (out *model.ReadRecordListOut, err error) { + out = &model.ReadRecordListOut{} + m := dao.ReadRecords.Ctx(ctx) + if in.UserId != 0 { + m = m.Where(dao.ReadRecords.Columns().UserId, in.UserId) + } + if in.BookId != 0 { + m = m.Where(dao.ReadRecords.Columns().BookId, in.BookId) + } + if in.ChapterId != 0 { + m = m.Where(dao.ReadRecords.Columns().ChapterId, in.ChapterId) + } + if err = m.Page(in.Page, in.Size).ScanAndCount(&out.List, &out.Total, false); err != nil { + return + } + return +} + +// Create adds a new read record +func (s *sReadRecord) Create(ctx context.Context, in *model.ReadRecordAddIn) (out *model.ReadRecordCRUDOut, err error) { + if _, err := dao.ReadRecords.Ctx(ctx).Data(do.ReadRecords{ + UserId: in.UserId, + BookId: in.BookId, + ChapterId: in.ChapterId, + }).Insert(); err != nil { + return nil, ecode.Fail.Sub("read_record_create_failed") + } + return &model.ReadRecordCRUDOut{Success: true}, nil +} + +// Delete removes a read record by id +func (s *sReadRecord) Delete(ctx context.Context, in *model.ReadRecordDelIn) (out *model.ReadRecordCRUDOut, err error) { + exist, err := dao.ReadRecords.Ctx(ctx). + WherePri(in.Id). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("read_record_query_failed") + } + if !exist { + return nil, ecode.NotFound.Sub("read_record_not_found") + } + _, err = dao.ReadRecords.Ctx(ctx).WherePri(in.Id).Delete() + if err != nil { + return nil, ecode.Fail.Sub("read_record_delete_failed") + } + return &model.ReadRecordCRUDOut{Success: true}, nil +} diff --git a/internal/logic/tag/tag.go b/internal/logic/tag/tag.go new file mode 100644 index 0000000..9390e39 --- /dev/null +++ b/internal/logic/tag/tag.go @@ -0,0 +1,119 @@ +package tag + +import ( + "context" + "server/internal/dao" + "server/internal/model" + "server/internal/model/do" + "server/internal/service" + "server/utility/ecode" +) + +type sTag struct{} + +func New() service.ITag { + return &sTag{} +} + +func init() { + service.RegisterTag(New()) +} + +// List retrieves a paginated list of tags +func (s *sTag) List(ctx context.Context, in *model.TagListIn) (out *model.TagListOut, err error) { + out = &model.TagListOut{} + m := dao.Tags.Ctx(ctx) + if in.Name != "" { + m = m.Where(dao.Tags.Columns().Name+" like ?", "%"+in.Name+"%") + } + if in.Type != 0 { + m = m.Where(dao.Tags.Columns().Type, in.Type) + } + if err = m.Page(in.Page, in.Size).ScanAndCount(&out.List, &out.Total, false); err != nil { + return + } + return +} + +func (s *sTag) Create(ctx context.Context, in *model.TagAddIn) (out *model.TagCRUDOut, err error) { + exist, err := dao.Tags.Ctx(ctx). + Where(dao.Tags.Columns().Name, in.Name). + Where(dao.Tags.Columns().Type, in.Type). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("tag_query_failed") + } + if exist { + return nil, ecode.Params.Sub("tag_exists") + } + + if _, err := dao.Tags.Ctx(ctx).Data(do.Tags{ + Name: in.Name, + Type: in.Type, + }).Insert(); err != nil { + return nil, ecode.Fail.Sub("tag_create_failed") + } + + return &model.TagCRUDOut{ + Success: true, + }, nil +} + +func (s *sTag) Update(ctx context.Context, in *model.TagEditIn) (out *model.TagCRUDOut, err error) { + exist, err := dao.Tags.Ctx(ctx). + WherePri(in.Id). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("tag_query_failed") + } + if !exist { + return nil, ecode.NotFound.Sub("tag_not_found") + } + + exist, err = dao.Tags.Ctx(ctx). + Where(dao.Tags.Columns().Name, in.Name). + Where(dao.Tags.Columns().Type, in.Type). + Where("id != ?", in.Id). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("tag_query_failed") + } + if exist { + return nil, ecode.Params.Sub("tag_exists") + } + + _, err = dao.Tags.Ctx(ctx). + WherePri(in.Id). + Data(do.Tags{ + Name: in.Name, + Type: in.Type, + }).Update() + if err != nil { + return nil, ecode.Fail.Sub("tag_update_failed") + } + + return &model.TagCRUDOut{ + Success: true, + }, nil +} + +func (s *sTag) Delete(ctx context.Context, in *model.TagDelIn) (out *model.TagCRUDOut, err error) { + exist, err := dao.Tags.Ctx(ctx). + WherePri(in.Id). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("tag_query_failed") + } + if !exist { + return nil, ecode.NotFound.Sub("tag_not_found") + } + + _, err = dao.Tags.Ctx(ctx).WherePri(in.Id).Delete() + if err != nil { + return nil, ecode.Fail.Sub("tag_delete_failed") + } + + return &model.TagCRUDOut{ + Success: true, + }, nil +} diff --git a/internal/logic/user/user.go b/internal/logic/user/user.go new file mode 100644 index 0000000..9f0c2ad --- /dev/null +++ b/internal/logic/user/user.go @@ -0,0 +1,136 @@ +package user + +import ( + "context" + "server/internal/dao" + "server/internal/model" + "server/internal/model/do" + "server/internal/model/entity" + "server/internal/service" + "server/utility/ecode" + "server/utility/encrypt" + "server/utility/jwt" + "strings" +) + +type sUser struct{} + +func New() service.IUser { + return &sUser{} +} +func init() { + service.RegisterUser(New()) +} + +func (s *sUser) Login(ctx context.Context, in *model.UserLoginIn) (out *model.UserLoginOut, err error) { + user, err := dao.Users.Ctx(ctx).Where(do.Users{Email: in.Email}).One() + if err != nil { + return nil, ecode.Fail.Sub("database_query_failed") + } + if user == nil { + return nil, ecode.Auth // 账户名或密码不正确 + } + var entityUser entity.Users + if err = user.Struct(&entityUser); err != nil { + return nil, ecode.Fail.Sub("data_conversion_failed") + } + if !encrypt.ComparePassword(entityUser.PasswordHash, in.Password) { + return nil, ecode.Password // 密码不正确 + } + token, err := jwt.GenerateToken(&jwt.TokenIn{UserId: entityUser.Id, Role: "user"}) + if err != nil { + return nil, ecode.Fail.Sub("token_generation_failed") + } + return &model.UserLoginOut{Token: token}, nil +} + +func (s *sUser) Register(ctx context.Context, in *model.UserRegisterIn) (out *model.UserRegisterOut, err error) { + if in.Password != in.Password2 { + return nil, ecode.Password.Sub("password_mismatch") + } + exist, err := dao.Users.Ctx(ctx).Where(do.Users{Email: in.Email}).Count() + if err != nil { + return nil, ecode.Fail.Sub("database_query_failed") + } + if exist > 0 { + return nil, ecode.EmailExist // 该邮箱已被注册 + } + hash, err := encrypt.EncryptPassword(in.Password) + if err != nil { + return nil, ecode.Fail.Sub("password_encryption_failed") + } + _, err = dao.Users.Ctx(ctx).Data(do.Users{ + Email: in.Email, + PasswordHash: hash, + Username: strings.Split(in.Email, "@")[0], + }).Insert() + if err != nil { + return nil, ecode.Fail.Sub("registration_failed") + } + return &model.UserRegisterOut{Success: true}, nil +} + +func (s *sUser) Info(ctx context.Context, in *model.UserInfoIn) (out *model.UserInfoOut, err error) { + user, err := dao.Users.Ctx(ctx).Where(do.Users{Id: in.UserId}).One() + if err != nil { + return nil, ecode.Fail.Sub("database_query_failed") + } + if user == nil { + return nil, ecode.Auth.Sub("user_not_found") + } + var entityUser entity.Users + if err = user.Struct(&entityUser); err != nil { + return nil, ecode.Fail.Sub("data_conversion_failed") + } + return &model.UserInfoOut{ + UserId: entityUser.Id, + Username: entityUser.Username, + Email: entityUser.Email, + Avatar: entityUser.Avatar, + Points: entityUser.Points, // 如有积分表可补充 + }, nil +} + +func (s *sUser) Delete(ctx context.Context, in *model.UserDeleteIn) (out *model.UserDeleteOut, err error) { + // FIXME + + return &model.UserDeleteOut{Success: true}, nil +} + +func (s *sUser) Code(ctx context.Context, in *model.UserCodeIn) (out *model.UserCodeOut, err error) { + exist, err := dao.Users.Ctx(ctx).Where(do.Users{Email: in.Email}).Exist() + if err != nil { + return nil, ecode.Fail.Sub("database_query_failed") + } + if !exist { + return nil, ecode.Params.Sub("email_not_found") + } + return &model.UserCodeOut{Success: true}, nil +} + +func (s *sUser) EditPass(ctx context.Context, in *model.UserEditPassIn) (out *model.UserEditPassOut, err error) { + exist, err := dao.Users.Ctx(ctx).Where(do.Users{Email: in.Email}).Exist() + if err != nil { + return nil, ecode.Fail.Sub("database_query_failed") + } + if !exist { + return nil, ecode.Params.Sub("email_not_found") + } + if in.Sign != "123456" { + return nil, ecode.Params.Sub("sign_error") + } + if in.Password != in.Password2 { + return nil, ecode.Password.Sub("password_mismatch") + } + hash, err := encrypt.EncryptPassword(in.Password) + if err != nil { + return nil, ecode.Fail.Sub("password_encryption_failed") + } + _, err = dao.Users.Ctx(ctx).Where(do.Users{Email: in.Email}).Data(do.Users{PasswordHash: hash}).Update() + if err != nil { + return nil, ecode.Fail.Sub("password_update_failed") + } + return &model.UserEditPassOut{ + Success: true, + }, nil +} diff --git a/internal/logic/user_follow_author/user_follow_author.go b/internal/logic/user_follow_author/user_follow_author.go new file mode 100644 index 0000000..b39922e --- /dev/null +++ b/internal/logic/user_follow_author/user_follow_author.go @@ -0,0 +1,66 @@ +package user_follow_author + +import ( + "context" + "server/internal/dao" + "server/internal/model" + "server/internal/model/do" + "server/utility/ecode" +) + +type sUserFollowAuthor struct{} + +// List retrieves a paginated list of user follow authors +func (s *sUserFollowAuthor) List(ctx context.Context, in *model.UserFollowAuthorListIn) (out *model.UserFollowAuthorListOut, err error) { + out = &model.UserFollowAuthorListOut{} + m := dao.UserFollowAuthors.Ctx(ctx) + if in.UserId != 0 { + m = m.Where(dao.UserFollowAuthors.Columns().UserId, in.UserId) + } + if in.AuthorId != 0 { + m = m.Where(dao.UserFollowAuthors.Columns().AuthorId, in.AuthorId) + } + if err = m.Page(in.Page, in.Size).ScanAndCount(&out.List, &out.Total, false); err != nil { + return + } + return +} + +// Create adds a new user follow author +func (s *sUserFollowAuthor) Create(ctx context.Context, in *model.UserFollowAuthorAddIn) (out *model.UserFollowAuthorCRUDOut, err error) { + exist, err := dao.UserFollowAuthors.Ctx(ctx). + Where(dao.UserFollowAuthors.Columns().UserId, in.UserId). + Where(dao.UserFollowAuthors.Columns().AuthorId, in.AuthorId). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("user_follow_author_query_failed") + } + if exist { + return nil, ecode.Params.Sub("user_follow_author_exists") + } + if _, err := dao.UserFollowAuthors.Ctx(ctx).Data(do.UserFollowAuthors{ + UserId: in.UserId, + AuthorId: in.AuthorId, + }).Insert(); err != nil { + return nil, ecode.Fail.Sub("user_follow_author_create_failed") + } + return &model.UserFollowAuthorCRUDOut{Success: true}, nil +} + +// Delete removes a user follow author by id +func (s *sUserFollowAuthor) Delete(ctx context.Context, in *model.UserFollowAuthorDelIn) (out *model.UserFollowAuthorCRUDOut, err error) { + exist, err := dao.UserFollowAuthors.Ctx(ctx). + WherePri(in.Id). + Exist() + if err != nil { + return nil, ecode.Fail.Sub("user_follow_author_query_failed") + } + if !exist { + return nil, ecode.NotFound.Sub("user_follow_author_not_found") + } + _, err = dao.UserFollowAuthors.Ctx(ctx).WherePri(in.Id).Delete() + if err != nil { + return nil, ecode.Fail.Sub("user_follow_author_delete_failed") + } + return &model.UserFollowAuthorCRUDOut{Success: true}, nil +} diff --git a/internal/middleware/auth.go b/internal/middleware/auth.go new file mode 100644 index 0000000..9c632c9 --- /dev/null +++ b/internal/middleware/auth.go @@ -0,0 +1,52 @@ +package middleware + +import ( + "server/utility/ecode" + "server/utility/jwt" + "strings" + + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/os/glog" +) + +// Auth 是用于权限验证的中间件。 +// +// 它会从请求头中读取 Authorization 字段,验证 JWT Token 的合法性。 +// 如果请求未携带 Token,则默认赋予 "guest" 权限。 +// 如果 Token 存在且合法,则将用户信息(userId、permission、jti)注入到请求上下文中。 +// +// Token 应采用 Bearer 方案,例如: +// +// Authorization: Bearer +// +// 参数: +// +// r *ghttp.Request - 当前的请求对象,由 ghttp 框架自动注入。 +// +// 行为: +// - 若无 Token:设定 permission 为 guest,放行请求。 +// - 若 Token 格式非法或解析失败:终止请求并返回错误。 +// - 若 Token 合法:将用户信息写入上下文,继续执行下一个中间件或处理函数。 +func Auth(r *ghttp.Request) { + token := r.GetHeader("Authorization") + ctx := r.GetCtx() + if token == "" { + glog.Infof(ctx, "未登录用户访问: %s %s", r.URL.Path, r.Method) + r.SetCtxVar("role", "guest") + } else { + if !strings.HasPrefix(token, "Bearer ") { + r.SetError(ecode.InvalidOperation.Sub("invalid_token_format")) + return + } + tokenOut, err := jwt.ParseToken(token) + if err != nil { + r.SetError(err) + return + } + r.SetCtxVar("id", tokenOut.UserId) + r.SetCtxVar("role", tokenOut.Role) + r.SetCtxVar("jti", tokenOut.JTI) + glog.Infof(ctx, "%s用户Id:%d 访问: %s %s", tokenOut.Role, tokenOut.UserId, r.URL.Path, r.Method) + } + r.Middleware.Next() +} diff --git a/internal/middleware/casbin.go b/internal/middleware/casbin.go new file mode 100644 index 0000000..c904b25 --- /dev/null +++ b/internal/middleware/casbin.go @@ -0,0 +1,29 @@ +package middleware + +import ( + "server/utility/ecode" + "server/utility/myCasbin" + + "github.com/gogf/gf/v2/net/ghttp" +) + +// Casbin 是用于访问权限控制的中间件。 +// +// 该中间件基于 Casbin 权限控制框架,校验当前用户是否有权访问指定的 URL 和请求方法。 +// 用户权限从请求上下文中的 "permission" 字段获取,该字段通常由前置中间件(如 Auth)注入。 +// +// 参数: +// +// r *ghttp.Request - 当前的 HTTP 请求对象,由框架自动传入。 +// +// 行为: +// - 如果权限验证未通过:终止请求,返回权限不足的错误(ecode.Denied)。 +// - 如果权限验证通过:继续执行后续中间件或处理逻辑。 +func Casbin(r *ghttp.Request) { + role := r.GetCtxVar("role").String() + if !myCasbin.GetMyCasbin().HasPermission(role, r.URL.Path, r.Method) { + r.SetError(ecode.Denied) + return + } + r.Middleware.Next() +} diff --git a/internal/middleware/exit.go b/internal/middleware/exit.go new file mode 100644 index 0000000..dba705b --- /dev/null +++ b/internal/middleware/exit.go @@ -0,0 +1,14 @@ +package middleware + +import ( + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/net/ghttp" +) + +func Exit(r *ghttp.Request, err error) { + r.Response.WriteJsonExit(ghttp.DefaultHandlerResponse{ + Code: gerror.Code(err).Code(), + Message: gerror.Code(err).Message(), + Data: nil, + }) +} diff --git a/internal/middleware/language.go b/internal/middleware/language.go new file mode 100644 index 0000000..0c54d8f --- /dev/null +++ b/internal/middleware/language.go @@ -0,0 +1,20 @@ +package middleware + +import ( + "server/utility/i18n" + + "github.com/gogf/gf/v2/net/ghttp" +) + +// Language 语言检测中间件 +// 从请求头或查询参数中检测语言设置,并设置到上下文中 +func Language(r *ghttp.Request) { + // 获取语言设置 + lang := i18n.GetLanguage(r.GetCtx()) + + // 将语言设置到上下文中,供后续使用 + r.SetCtxVar("language", lang) + + // 继续下一个中间件 + r.Middleware.Next() +} diff --git a/internal/middleware/response.go b/internal/middleware/response.go new file mode 100644 index 0000000..3d3a101 --- /dev/null +++ b/internal/middleware/response.go @@ -0,0 +1,69 @@ +package middleware + +import ( + "net/http" + "server/utility/ecode" + "server/utility/i18n" + + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/os/gctx" + "github.com/gogf/gf/v2/os/glog" + "github.com/gogf/gf/v2/util/gconv" +) + +func Response(r *ghttp.Request) { + r.Middleware.Next() + + if r.Response.BufferLength() > 0 { + return + } + + var ( + msg string + err = r.GetError() + res = r.GetHandlerResponse() + code = gerror.Code(err) + ctx = r.GetCtx() + ) + glog.Debug(gctx.New(), "错误", err) + if err != nil { + if gconv.String(code.Detail()) != "customer" && code.Code() != 51 { + msg = ecode.Fail.MessageI18n(ctx) + } else if code.Code() == 51 { + msg = ecode.Params.MessageI18n(ctx) + } else { + // 尝试从国际化系统获取消息 + msg = i18n.T(ctx, code.Message()) + if msg == code.Message() { + // 如果没有找到国际化消息,使用原始消息 + msg = code.Message() + } + } + } else if r.Response.Status > 0 && r.Response.Status != http.StatusOK { + // HTTP状态码错误消息的国际化 + switch r.Response.Status { + case http.StatusNotFound: + code = gcode.CodeNotFound + msg = i18n.T(ctx, "not_found") + case http.StatusForbidden: + code = gcode.CodeNotAuthorized + msg = i18n.T(ctx, "forbidden") + case http.StatusUnauthorized: + code = gcode.CodeNotAuthorized + msg = i18n.T(ctx, "unauthorized") + default: + code = gcode.CodeUnknown + msg = i18n.T(ctx, "unknown_error") + } + } else { + code = gcode.CodeOK + msg = i18n.T(ctx, "success") + } + r.Response.WriteJson(ghttp.DefaultHandlerResponse{ + Code: code.Code(), + Message: msg, + Data: res, + }) +} diff --git a/internal/model/admin.go b/internal/model/admin.go new file mode 100644 index 0000000..9c15b71 --- /dev/null +++ b/internal/model/admin.go @@ -0,0 +1,31 @@ +package model + +type Admin struct { +} +type AdminLoginIn struct { + Username string + Password string +} + +type AdminLoginOut struct { + Token string +} + +type AdminInfoIn struct { + AdminId int64 // 管理员ID +} + +type AdminInfoOut struct { + AdminId int64 // 管理员ID + Username string // 用户名 +} + +type AdminEditPassIn struct { + AdminId int64 // 管理员ID + OldPass string // 旧密码 + NewPass string // 新密码 +} + +type AdminEditPassOut struct { + Success bool // 是否成功 +} diff --git a/internal/model/base.go b/internal/model/base.go new file mode 100644 index 0000000..0a6ce3a --- /dev/null +++ b/internal/model/base.go @@ -0,0 +1,13 @@ +package model + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// Base 包含数据库表常见的公共字段 +type Base struct { + Id int64 `json:"id" orm:"id,primary"` // 主键 ID + CreatedAt *gtime.Time `json:"created_at" orm:"created_at"` // 创建时间 + UpdatedAt *gtime.Time `json:"updated_at" orm:"updated_at"` // 更新时间 + DeletedAt *gtime.Time `json:"deleted_at" orm:"deleted_at"` // 软删除时间 +} diff --git a/internal/model/book.go b/internal/model/book.go new file mode 100644 index 0000000..e4b2c96 --- /dev/null +++ b/internal/model/book.go @@ -0,0 +1,64 @@ +package model + +import "github.com/gogf/gf/v2/frame/g" + +type Book struct { + g.Meta `orm:"table:books"` + Id int64 `json:"id"` + AuthorId int64 `json:"authorId"` + CategoryId int64 `json:"categoryId"` + Title string `json:"title"` + CoverUrl string `json:"coverUrl"` + Description string `json:"description"` + Status int `json:"status"` + WordsCount int `json:"wordsCount"` + ChaptersCount int `json:"chaptersCount"` + LatestChapterId int64 `json:"latestChapterId"` + Rating float64 `json:"rating"` + ReadCount int64 `json:"readCount"` + Tags string `json:"tags"` + IsRecommended int `json:"isRecommended"` +} + +type BookListIn struct { + Page int + Size int + Title string + CategoryId int64 + AuthorId int64 + Status int + IsRecommended int +} +type BookListOut struct { + Total int + List []Book +} + +type BookAddIn struct { + AuthorId int64 + CategoryId int64 + Title string + CoverUrl string + Description string + Status int + Tags string + IsRecommended int +} +type BookEditIn struct { + Id int64 + AuthorId int64 + CategoryId int64 + Title string + CoverUrl string + Description string + Status int + Tags string + IsRecommended int +} +type BookDelIn struct { + Id int64 +} + +type BookCRUDOut struct { + Success bool +} diff --git a/internal/model/category.go b/internal/model/category.go new file mode 100644 index 0000000..8ebee78 --- /dev/null +++ b/internal/model/category.go @@ -0,0 +1,38 @@ +package model + +import "github.com/gogf/gf/v2/frame/g" + +type Category struct { + g.Meta `orm:"table:categories"` + Id int64 `json:"id" orm:"id"` // 分类ID + Name string `json:"name" orm:"name"` // 分类名称 + Type int `json:type orm:"type"` // 类型,1 男频,2 女频 +} + +type CategoryListIn struct { + Page int + Size int + Name string + Type int +} +type CategoryListOut struct { + Total int + List []Category +} + +type CategoryAddIn struct { + Name string + Type int // 类型,1 男频,2 女频 +} +type CategoryEditIn struct { + Id int + Name string + Type int // 类型,1 男频,2 女频 +} +type CategoryDelIn struct { + Id int +} + +type CategoryCRUDOut struct { + Success bool +} diff --git a/internal/model/chapter.go b/internal/model/chapter.go new file mode 100644 index 0000000..30a04af --- /dev/null +++ b/internal/model/chapter.go @@ -0,0 +1,54 @@ +package model + +import "github.com/gogf/gf/v2/frame/g" + +type Chapter struct { + g.Meta `orm:"table:chapters"` + Id int64 `json:"id"` + BookId int64 `json:"bookId"` + Title string `json:"title"` + Content string `json:"content"` + WordCount int `json:"wordCount"` + Sort int `json:"sort"` + IsLocked int `json:"isLocked"` + RequiredScore int `json:"requiredScore"` +} + +type ChapterListIn struct { + Page int + Size int + BookId int64 + Title string + IsLocked int +} +type ChapterListOut struct { + Total int + List []Chapter +} + +type ChapterAddIn struct { + BookId int64 + Title string + Content string + WordCount int + Sort int + IsLocked int + RequiredScore int +} +type ChapterEditIn struct { + Id int64 + BookId int64 + Title string + Content string + WordCount int + Sort int + IsLocked int + RequiredScore int +} +type ChapterDelIn struct { + Id int64 +} + +type ChapterCRUDOut struct { + Success bool +} diff --git a/internal/model/do/admins.go b/internal/model/do/admins.go new file mode 100644 index 0000000..d70b983 --- /dev/null +++ b/internal/model/do/admins.go @@ -0,0 +1,21 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// Admins is the golang structure of table admins for DAO operations like Where/Data. +type Admins struct { + g.Meta `orm:"table:admins, do:true"` + Id interface{} // 管理员ID + Username interface{} // 管理员用户名 + PasswordHash interface{} // 密码哈希 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 + DeletedAt *gtime.Time // 软删除时间戳 +} diff --git a/internal/model/do/authors.go b/internal/model/do/authors.go new file mode 100644 index 0000000..7600116 --- /dev/null +++ b/internal/model/do/authors.go @@ -0,0 +1,23 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// Authors is the golang structure of table authors for DAO operations like Where/Data. +type Authors struct { + g.Meta `orm:"table:authors, do:true"` + Id interface{} // 作者ID + UserId interface{} // 用户ID + PenName interface{} // 笔名 + Bio interface{} // 作者简介 + Status interface{} // 状态:1=正常,2=禁用 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 + DeletedAt *gtime.Time // 软删除时间戳 +} diff --git a/internal/model/do/book_ratings.go b/internal/model/do/book_ratings.go new file mode 100644 index 0000000..b555d7c --- /dev/null +++ b/internal/model/do/book_ratings.go @@ -0,0 +1,21 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// BookRatings is the golang structure of table book_ratings for DAO operations like Where/Data. +type BookRatings struct { + g.Meta `orm:"table:book_ratings, do:true"` + Id interface{} // 评分ID + UserId interface{} // 用户ID + BookId interface{} // 小说ID + Score interface{} // 评分(0~10) + Comment interface{} // 用户评论 + CreatedAt *gtime.Time // 创建时间 +} diff --git a/internal/model/do/books.go b/internal/model/do/books.go new file mode 100644 index 0000000..2193b56 --- /dev/null +++ b/internal/model/do/books.go @@ -0,0 +1,32 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// Books is the golang structure of table books for DAO operations like Where/Data. +type Books struct { + g.Meta `orm:"table:books, do:true"` + Id interface{} // 小说ID + AuthorId interface{} // 作者ID + CategoryId interface{} // 分类ID + Title interface{} // 小说标题 + CoverUrl interface{} // 封面图片URL + Description interface{} // 小说简介 + Status interface{} // 状态:1=连载中,2=完结,3=下架 + WordsCount interface{} // 字数 + ChaptersCount interface{} // 章节数 + LatestChapterId interface{} // 最新章节ID + Rating interface{} // 评分(0.00~10.00) + ReadCount interface{} // 阅读人数 + Tags interface{} // 标签(逗号分隔) + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 + DeletedAt *gtime.Time // 软删除时间戳 + IsRecommended interface{} // 是否推荐:0=否,1=是 +} diff --git a/internal/model/do/bookshelves.go b/internal/model/do/bookshelves.go new file mode 100644 index 0000000..ba83e3f --- /dev/null +++ b/internal/model/do/bookshelves.go @@ -0,0 +1,22 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// Bookshelves is the golang structure of table bookshelves for DAO operations like Where/Data. +type Bookshelves struct { + g.Meta `orm:"table:bookshelves, do:true"` + Id interface{} // 记录ID + UserId interface{} // 用户ID + BookId interface{} // 小说ID + AddedAt *gtime.Time // 加入书架时间 + LastReadChapterId interface{} // 最后阅读章节ID + LastReadPercent interface{} // 阅读进度百分比(0.00~100.00) + LastReadAt *gtime.Time // 最后阅读时间 +} diff --git a/internal/model/do/categories.go b/internal/model/do/categories.go new file mode 100644 index 0000000..933fee6 --- /dev/null +++ b/internal/model/do/categories.go @@ -0,0 +1,21 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// Categories is the golang structure of table categories for DAO operations like Where/Data. +type Categories struct { + g.Meta `orm:"table:categories, do:true"` + Id interface{} // 分类ID + Name interface{} // 分类名称 + Type interface{} // 分类类型:1=男频, 2=女频 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 + DeletedAt *gtime.Time // 软删除时间戳 +} diff --git a/internal/model/do/chapters.go b/internal/model/do/chapters.go new file mode 100644 index 0000000..5d0a20a --- /dev/null +++ b/internal/model/do/chapters.go @@ -0,0 +1,26 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// Chapters is the golang structure of table chapters for DAO operations like Where/Data. +type Chapters struct { + g.Meta `orm:"table:chapters, do:true"` + Id interface{} // 章节ID + BookId interface{} // 小说ID + Title interface{} // 章节标题 + Content interface{} // 章节内容 + WordCount interface{} // 章节字数 + Sort interface{} // 排序序号 + IsLocked interface{} // 是否锁定:0=免费,1=需积分解锁 + RequiredScore interface{} // 解锁该章节所需积分 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 + DeletedAt *gtime.Time // 软删除时间戳 +} diff --git a/internal/model/do/feedbacks.go b/internal/model/do/feedbacks.go new file mode 100644 index 0000000..948ad86 --- /dev/null +++ b/internal/model/do/feedbacks.go @@ -0,0 +1,21 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// Feedbacks is the golang structure of table feedbacks for DAO operations like Where/Data. +type Feedbacks struct { + g.Meta `orm:"table:feedbacks, do:true"` + Id interface{} // 反馈ID + UserId interface{} // 用户ID + Content interface{} // 反馈内容 + Status interface{} // 处理状态:1=未处理,2=处理中,3=已处理 + CreatedAt *gtime.Time // 反馈时间 + UpdatedAt *gtime.Time // 更新时间 +} diff --git a/internal/model/do/read_records.go b/internal/model/do/read_records.go new file mode 100644 index 0000000..2b871a0 --- /dev/null +++ b/internal/model/do/read_records.go @@ -0,0 +1,20 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// ReadRecords is the golang structure of table read_records for DAO operations like Where/Data. +type ReadRecords struct { + g.Meta `orm:"table:read_records, do:true"` + Id interface{} // 记录ID + UserId interface{} // 用户ID + BookId interface{} // 小说ID + ChapterId interface{} // 章节ID + ReadAt *gtime.Time // 阅读时间 +} diff --git a/internal/model/do/tags.go b/internal/model/do/tags.go new file mode 100644 index 0000000..c8996ba --- /dev/null +++ b/internal/model/do/tags.go @@ -0,0 +1,21 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// Tags is the golang structure of table tags for DAO operations like Where/Data. +type Tags struct { + g.Meta `orm:"table:tags, do:true"` + Id interface{} // 标签ID + Name interface{} // 标签名称 + Type interface{} // 标签类型:1=主题, 2=角色, 3=情节 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 + DeletedAt *gtime.Time // 软删除时间戳 +} diff --git a/internal/model/do/user_chapter_purchases.go b/internal/model/do/user_chapter_purchases.go new file mode 100644 index 0000000..e7be83f --- /dev/null +++ b/internal/model/do/user_chapter_purchases.go @@ -0,0 +1,21 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// UserChapterPurchases is the golang structure of table user_chapter_purchases for DAO operations like Where/Data. +type UserChapterPurchases struct { + g.Meta `orm:"table:user_chapter_purchases, do:true"` + Id interface{} // 购买记录ID + UserId interface{} // 用户ID + BookId interface{} // 小说ID + ChapterId interface{} // 章节ID + PointsUsed interface{} // 消耗积分数 + PurchaseTime *gtime.Time // 购买时间 +} diff --git a/internal/model/do/user_follow_authors.go b/internal/model/do/user_follow_authors.go new file mode 100644 index 0000000..eaa947f --- /dev/null +++ b/internal/model/do/user_follow_authors.go @@ -0,0 +1,19 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// UserFollowAuthors is the golang structure of table user_follow_authors for DAO operations like Where/Data. +type UserFollowAuthors struct { + g.Meta `orm:"table:user_follow_authors, do:true"` + Id interface{} // 关注ID + UserId interface{} // 用户ID + AuthorId interface{} // 作者ID + FollowedAt *gtime.Time // 关注时间 +} diff --git a/internal/model/do/user_points.go b/internal/model/do/user_points.go new file mode 100644 index 0000000..9efec6d --- /dev/null +++ b/internal/model/do/user_points.go @@ -0,0 +1,19 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// UserPoints is the golang structure of table user_points for DAO operations like Where/Data. +type UserPoints struct { + g.Meta `orm:"table:user_points, do:true"` + Id interface{} // 积分账户ID + UserId interface{} // 用户ID + PointsBalance interface{} // 当前积分余额 + UpdatedAt *gtime.Time // 更新时间 +} diff --git a/internal/model/do/user_points_logs.go b/internal/model/do/user_points_logs.go new file mode 100644 index 0000000..996641e --- /dev/null +++ b/internal/model/do/user_points_logs.go @@ -0,0 +1,22 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// UserPointsLogs is the golang structure of table user_points_logs for DAO operations like Where/Data. +type UserPointsLogs struct { + g.Meta `orm:"table:user_points_logs, do:true"` + Id interface{} // 积分流水ID + UserId interface{} // 用户ID + ChangeType interface{} // 变动类型,例如 earn、spend、refund 等 + PointsChange interface{} // 积分变化数,正数增加,负数减少 + RelatedOrderId interface{} // 关联订单ID + Description interface{} // 变动说明 + CreatedAt *gtime.Time // 变动时间 +} diff --git a/internal/model/do/users.go b/internal/model/do/users.go new file mode 100644 index 0000000..8157e77 --- /dev/null +++ b/internal/model/do/users.go @@ -0,0 +1,24 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// Users is the golang structure of table users for DAO operations like Where/Data. +type Users struct { + g.Meta `orm:"table:users, do:true"` + Id interface{} // 用户ID + Username interface{} // 用户名 + PasswordHash interface{} // 密码哈希 + Avatar interface{} // 头像URL + Email interface{} // 邮箱 + Points interface{} // 积分 + CreatedAt *gtime.Time // 注册时间 + UpdatedAt *gtime.Time // 更新时间 + DeletedAt *gtime.Time // 软删除时间戳 +} diff --git a/internal/model/entity/admins.go b/internal/model/entity/admins.go new file mode 100644 index 0000000..d19c0b1 --- /dev/null +++ b/internal/model/entity/admins.go @@ -0,0 +1,19 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// Admins is the golang structure for table admins. +type Admins struct { + Id int64 `json:"id" orm:"id" description:"管理员ID"` // 管理员ID + Username string `json:"username" orm:"username" description:"管理员用户名"` // 管理员用户名 + PasswordHash string `json:"passwordHash" orm:"password_hash" description:"密码哈希"` // 密码哈希 + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间 + UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间 + DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳 +} diff --git a/internal/model/entity/authors.go b/internal/model/entity/authors.go new file mode 100644 index 0000000..9bb9ba8 --- /dev/null +++ b/internal/model/entity/authors.go @@ -0,0 +1,21 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// Authors is the golang structure for table authors. +type Authors struct { + Id int64 `json:"id" orm:"id" description:"作者ID"` // 作者ID + UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID + PenName string `json:"penName" orm:"pen_name" description:"笔名"` // 笔名 + Bio string `json:"bio" orm:"bio" description:"作者简介"` // 作者简介 + Status int `json:"status" orm:"status" description:"状态:1=正常,2=禁用"` // 状态:1=正常,2=禁用 + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间 + UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间 + DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳 +} diff --git a/internal/model/entity/book_ratings.go b/internal/model/entity/book_ratings.go new file mode 100644 index 0000000..777dee9 --- /dev/null +++ b/internal/model/entity/book_ratings.go @@ -0,0 +1,19 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// BookRatings is the golang structure for table book_ratings. +type BookRatings struct { + Id int64 `json:"id" orm:"id" description:"评分ID"` // 评分ID + UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID + BookId int64 `json:"bookId" orm:"book_id" description:"小说ID"` // 小说ID + Score float64 `json:"score" orm:"score" description:"评分(0~10)"` // 评分(0~10) + Comment string `json:"comment" orm:"comment" description:"用户评论"` // 用户评论 + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间 +} diff --git a/internal/model/entity/books.go b/internal/model/entity/books.go new file mode 100644 index 0000000..21b2c27 --- /dev/null +++ b/internal/model/entity/books.go @@ -0,0 +1,30 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// Books is the golang structure for table books. +type Books struct { + Id int64 `json:"id" orm:"id" description:"小说ID"` // 小说ID + AuthorId int64 `json:"authorId" orm:"author_id" description:"作者ID"` // 作者ID + CategoryId int64 `json:"categoryId" orm:"category_id" description:"分类ID"` // 分类ID + Title string `json:"title" orm:"title" description:"小说标题"` // 小说标题 + CoverUrl string `json:"coverUrl" orm:"cover_url" description:"封面图片URL"` // 封面图片URL + Description string `json:"description" orm:"description" description:"小说简介"` // 小说简介 + Status int `json:"status" orm:"status" description:"状态:1=连载中,2=完结,3=下架"` // 状态:1=连载中,2=完结,3=下架 + WordsCount int `json:"wordsCount" orm:"words_count" description:"字数"` // 字数 + ChaptersCount int `json:"chaptersCount" orm:"chapters_count" description:"章节数"` // 章节数 + LatestChapterId int64 `json:"latestChapterId" orm:"latest_chapter_id" description:"最新章节ID"` // 最新章节ID + Rating float64 `json:"rating" orm:"rating" description:"评分(0.00~10.00)"` // 评分(0.00~10.00) + ReadCount int64 `json:"readCount" orm:"read_count" description:"阅读人数"` // 阅读人数 + Tags string `json:"tags" orm:"tags" description:"标签(逗号分隔)"` // 标签(逗号分隔) + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间 + UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间 + DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳 + IsRecommended int `json:"isRecommended" orm:"is_recommended" description:"是否推荐:0=否,1=是"` // 是否推荐:0=否,1=是 +} diff --git a/internal/model/entity/bookshelves.go b/internal/model/entity/bookshelves.go new file mode 100644 index 0000000..d6f893b --- /dev/null +++ b/internal/model/entity/bookshelves.go @@ -0,0 +1,20 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// Bookshelves is the golang structure for table bookshelves. +type Bookshelves struct { + Id int64 `json:"id" orm:"id" description:"记录ID"` // 记录ID + UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID + BookId int64 `json:"bookId" orm:"book_id" description:"小说ID"` // 小说ID + AddedAt *gtime.Time `json:"addedAt" orm:"added_at" description:"加入书架时间"` // 加入书架时间 + LastReadChapterId int64 `json:"lastReadChapterId" orm:"last_read_chapter_id" description:"最后阅读章节ID"` // 最后阅读章节ID + LastReadPercent float64 `json:"lastReadPercent" orm:"last_read_percent" description:"阅读进度百分比(0.00~100.00)"` // 阅读进度百分比(0.00~100.00) + LastReadAt *gtime.Time `json:"lastReadAt" orm:"last_read_at" description:"最后阅读时间"` // 最后阅读时间 +} diff --git a/internal/model/entity/categories.go b/internal/model/entity/categories.go new file mode 100644 index 0000000..2907560 --- /dev/null +++ b/internal/model/entity/categories.go @@ -0,0 +1,19 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// Categories is the golang structure for table categories. +type Categories struct { + Id int64 `json:"id" orm:"id" description:"分类ID"` // 分类ID + Name string `json:"name" orm:"name" description:"分类名称"` // 分类名称 + Type int `json:"type" orm:"type" description:"分类类型:1=男频, 2=女频"` // 分类类型:1=男频, 2=女频 + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间 + UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间 + DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳 +} diff --git a/internal/model/entity/chapters.go b/internal/model/entity/chapters.go new file mode 100644 index 0000000..bb80cbe --- /dev/null +++ b/internal/model/entity/chapters.go @@ -0,0 +1,24 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// Chapters is the golang structure for table chapters. +type Chapters struct { + Id int64 `json:"id" orm:"id" description:"章节ID"` // 章节ID + BookId int64 `json:"bookId" orm:"book_id" description:"小说ID"` // 小说ID + Title string `json:"title" orm:"title" description:"章节标题"` // 章节标题 + Content string `json:"content" orm:"content" description:"章节内容"` // 章节内容 + WordCount int `json:"wordCount" orm:"word_count" description:"章节字数"` // 章节字数 + Sort int `json:"sort" orm:"sort" description:"排序序号"` // 排序序号 + IsLocked int `json:"isLocked" orm:"is_locked" description:"是否锁定:0=免费,1=需积分解锁"` // 是否锁定:0=免费,1=需积分解锁 + RequiredScore int `json:"requiredScore" orm:"required_score" description:"解锁该章节所需积分"` // 解锁该章节所需积分 + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间 + UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间 + DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳 +} diff --git a/internal/model/entity/feedbacks.go b/internal/model/entity/feedbacks.go new file mode 100644 index 0000000..a848110 --- /dev/null +++ b/internal/model/entity/feedbacks.go @@ -0,0 +1,19 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// Feedbacks is the golang structure for table feedbacks. +type Feedbacks struct { + Id int64 `json:"id" orm:"id" description:"反馈ID"` // 反馈ID + UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID + Content string `json:"content" orm:"content" description:"反馈内容"` // 反馈内容 + Status int `json:"status" orm:"status" description:"处理状态:1=未处理,2=处理中,3=已处理"` // 处理状态:1=未处理,2=处理中,3=已处理 + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"反馈时间"` // 反馈时间 + UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间 +} diff --git a/internal/model/entity/read_records.go b/internal/model/entity/read_records.go new file mode 100644 index 0000000..1f22b92 --- /dev/null +++ b/internal/model/entity/read_records.go @@ -0,0 +1,18 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// ReadRecords is the golang structure for table read_records. +type ReadRecords struct { + Id int64 `json:"id" orm:"id" description:"记录ID"` // 记录ID + UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID + BookId int64 `json:"bookId" orm:"book_id" description:"小说ID"` // 小说ID + ChapterId int64 `json:"chapterId" orm:"chapter_id" description:"章节ID"` // 章节ID + ReadAt *gtime.Time `json:"readAt" orm:"read_at" description:"阅读时间"` // 阅读时间 +} diff --git a/internal/model/entity/tags.go b/internal/model/entity/tags.go new file mode 100644 index 0000000..120ea02 --- /dev/null +++ b/internal/model/entity/tags.go @@ -0,0 +1,19 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// Tags is the golang structure for table tags. +type Tags struct { + Id int64 `json:"id" orm:"id" description:"标签ID"` // 标签ID + Name string `json:"name" orm:"name" description:"标签名称"` // 标签名称 + Type int `json:"type" orm:"type" description:"标签类型:1=主题, 2=角色, 3=情节"` // 标签类型:1=主题, 2=角色, 3=情节 + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"` // 创建时间 + UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间 + DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳 +} diff --git a/internal/model/entity/user_chapter_purchases.go b/internal/model/entity/user_chapter_purchases.go new file mode 100644 index 0000000..109ddb7 --- /dev/null +++ b/internal/model/entity/user_chapter_purchases.go @@ -0,0 +1,19 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// UserChapterPurchases is the golang structure for table user_chapter_purchases. +type UserChapterPurchases struct { + Id int64 `json:"id" orm:"id" description:"购买记录ID"` // 购买记录ID + UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID + BookId int64 `json:"bookId" orm:"book_id" description:"小说ID"` // 小说ID + ChapterId int64 `json:"chapterId" orm:"chapter_id" description:"章节ID"` // 章节ID + PointsUsed int `json:"pointsUsed" orm:"points_used" description:"消耗积分数"` // 消耗积分数 + PurchaseTime *gtime.Time `json:"purchaseTime" orm:"purchase_time" description:"购买时间"` // 购买时间 +} diff --git a/internal/model/entity/user_follow_authors.go b/internal/model/entity/user_follow_authors.go new file mode 100644 index 0000000..ed80fa8 --- /dev/null +++ b/internal/model/entity/user_follow_authors.go @@ -0,0 +1,17 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// UserFollowAuthors is the golang structure for table user_follow_authors. +type UserFollowAuthors struct { + Id int64 `json:"id" orm:"id" description:"关注ID"` // 关注ID + UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID + AuthorId int64 `json:"authorId" orm:"author_id" description:"作者ID"` // 作者ID + FollowedAt *gtime.Time `json:"followedAt" orm:"followed_at" description:"关注时间"` // 关注时间 +} diff --git a/internal/model/entity/user_points.go b/internal/model/entity/user_points.go new file mode 100644 index 0000000..f3339a2 --- /dev/null +++ b/internal/model/entity/user_points.go @@ -0,0 +1,17 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// UserPoints is the golang structure for table user_points. +type UserPoints struct { + Id int64 `json:"id" orm:"id" description:"积分账户ID"` // 积分账户ID + UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID + PointsBalance int `json:"pointsBalance" orm:"points_balance" description:"当前积分余额"` // 当前积分余额 + UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间 +} diff --git a/internal/model/entity/user_points_logs.go b/internal/model/entity/user_points_logs.go new file mode 100644 index 0000000..2d0ce38 --- /dev/null +++ b/internal/model/entity/user_points_logs.go @@ -0,0 +1,20 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// UserPointsLogs is the golang structure for table user_points_logs. +type UserPointsLogs struct { + Id int64 `json:"id" orm:"id" description:"积分流水ID"` // 积分流水ID + UserId int64 `json:"userId" orm:"user_id" description:"用户ID"` // 用户ID + ChangeType string `json:"changeType" orm:"change_type" description:"变动类型,例如 earn、spend、refund 等"` // 变动类型,例如 earn、spend、refund 等 + PointsChange int `json:"pointsChange" orm:"points_change" description:"积分变化数,正数增加,负数减少"` // 积分变化数,正数增加,负数减少 + RelatedOrderId int64 `json:"relatedOrderId" orm:"related_order_id" description:"关联订单ID"` // 关联订单ID + Description string `json:"description" orm:"description" description:"变动说明"` // 变动说明 + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"变动时间"` // 变动时间 +} diff --git a/internal/model/entity/users.go b/internal/model/entity/users.go new file mode 100644 index 0000000..4b95d1b --- /dev/null +++ b/internal/model/entity/users.go @@ -0,0 +1,22 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// Users is the golang structure for table users. +type Users struct { + Id int64 `json:"id" orm:"id" description:"用户ID"` // 用户ID + Username string `json:"username" orm:"username" description:"用户名"` // 用户名 + PasswordHash string `json:"passwordHash" orm:"password_hash" description:"密码哈希"` // 密码哈希 + Avatar string `json:"avatar" orm:"avatar" description:"头像URL"` // 头像URL + Email string `json:"email" orm:"email" description:"邮箱"` // 邮箱 + Points uint64 `json:"points" orm:"points" description:"积分"` // 积分 + CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"注册时间"` // 注册时间 + UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"` // 更新时间 + DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"软删除时间戳"` // 软删除时间戳 +} diff --git a/internal/model/feedback.go b/internal/model/feedback.go new file mode 100644 index 0000000..4c185f4 --- /dev/null +++ b/internal/model/feedback.go @@ -0,0 +1,30 @@ +package model + +import "github.com/gogf/gf/v2/frame/g" + +type Feedback struct { + g.Meta `orm:"table:feedbacks"` + Id int64 `json:"id"` + UserId int64 `json:"userId"` + Content string `json:"content"` + Status int `json:"status"` +} + +type FeedbackListIn struct { + Page int + Size int + UserId int64 + Status int +} +type FeedbackListOut struct { + Total int + List []Feedback +} + +type FeedbackAddIn struct { + UserId int64 + Content string +} +type FeedbackCRUDOut struct { + Success bool +} diff --git a/internal/model/read_record.go b/internal/model/read_record.go new file mode 100644 index 0000000..27f820d --- /dev/null +++ b/internal/model/read_record.go @@ -0,0 +1,36 @@ +package model + +import "github.com/gogf/gf/v2/frame/g" + +type ReadRecord struct { + g.Meta `orm:"table:read_records"` + Id int64 `json:"id"` + UserId int64 `json:"userId"` + BookId int64 `json:"bookId"` + ChapterId int64 `json:"chapterId"` + ReadAt int64 `json:"readAt"` +} + +type ReadRecordListIn struct { + Page int + Size int + UserId int64 + BookId int64 + ChapterId int64 +} +type ReadRecordListOut struct { + Total int + List []ReadRecord +} + +type ReadRecordAddIn struct { + UserId int64 + BookId int64 + ChapterId int64 +} +type ReadRecordDelIn struct { + Id int64 +} +type ReadRecordCRUDOut struct { + Success bool +} diff --git a/internal/model/tag.go b/internal/model/tag.go new file mode 100644 index 0000000..3420d91 --- /dev/null +++ b/internal/model/tag.go @@ -0,0 +1,38 @@ +package model + +import "github.com/gogf/gf/v2/frame/g" + +type Tag struct { + g.Meta `orm:"table:tags"` + Id int64 `json:"id"` + Name string `json:"name"` + Type int `json:"type"` // 1=主题, 2=角色, 3=情节 +} + +type TagListIn struct { + Page int + Size int + Name string + Type int +} +type TagListOut struct { + Total int + List []Tag +} + +type TagAddIn struct { + Name string + Type int +} +type TagEditIn struct { + Id int64 + Name string + Type int +} +type TagDelIn struct { + Id int64 +} + +type TagCRUDOut struct { + Success bool +} diff --git a/internal/model/upload.go b/internal/model/upload.go new file mode 100644 index 0000000..59d7292 --- /dev/null +++ b/internal/model/upload.go @@ -0,0 +1,47 @@ +package model + +import "github.com/gogf/gf/v2/net/ghttp" + +type UploadIn struct { + File *ghttp.UploadFile + Type string +} + +type UploadOut struct { + Url string +} +type OssOutput struct { + Url string +} + +type OssBytesInput struct { + Bytes []byte + Name string +} + +type OssGetFileInput struct { + FilePath string + Name string +} + +type OssUploadFileInput struct { + Filename string + File *ghttp.UploadFile +} + +type SMSCodeIn struct { + Phone string + Code string +} + +type SMSCodeOut struct { + Success bool +} + +type CaptchaIn struct { + Name string +} + +type CaptchaOut struct { + Success bool +} diff --git a/internal/model/user.go b/internal/model/user.go new file mode 100644 index 0000000..87847f3 --- /dev/null +++ b/internal/model/user.go @@ -0,0 +1,71 @@ +package model + +type UserLoginIn struct { + Email string // 用户名 + Password string // 密码 +} + +type UserLoginOut struct { + Token string // 登录令牌 +} + +type UserRegisterIn struct { + Email string // 用户名 + Password string // 密码 + Password2 string // 邮箱 +} + +type UserRegisterOut struct { + Success bool // 是否成功 +} + +type UserInfoIn struct { + UserId int64 // 用户ID +} + +type UserInfoOut struct { + UserId int64 // 用户ID + Username string // 用户名 + Email string // 邮箱 + Points uint64 // 积分 + Avatar string // 头像 +} + +type UserDeleteIn struct { + UserId int64 // 用户ID + Password string // 密码 +} + +type UserDeleteOut struct { + Success bool // 是否成功 +} + +type UserCodeIn struct { + Email string // 邮箱 +} + +type UserCodeOut struct { + Success bool // 是否成功 +} + +type UserEditPassIn struct { + Email string + Password string + Password2 string + Sign string +} + +type UserEditPassOut struct { + Success bool // 是否成功 +} +type VertifyCodeIn struct { + Email string + Code string +} + +type VertifyCodeOut struct { + Sign string +} + +type UserInfoAPI struct { +} diff --git a/internal/model/user_follow_author.go b/internal/model/user_follow_author.go new file mode 100644 index 0000000..1e6c380 --- /dev/null +++ b/internal/model/user_follow_author.go @@ -0,0 +1,33 @@ +package model + +import "github.com/gogf/gf/v2/frame/g" + +type UserFollowAuthor struct { + g.Meta `orm:"table:user_follow_authors"` + Id int64 `json:"id"` + UserId int64 `json:"userId"` + AuthorId int64 `json:"authorId"` + FollowedAt int64 `json:"followedAt"` +} + +type UserFollowAuthorListIn struct { + Page int + Size int + UserId int64 + AuthorId int64 +} +type UserFollowAuthorListOut struct { + Total int + List []UserFollowAuthor +} + +type UserFollowAuthorAddIn struct { + UserId int64 + AuthorId int64 +} +type UserFollowAuthorDelIn struct { + Id int64 +} +type UserFollowAuthorCRUDOut struct { + Success bool +} diff --git a/internal/packed/packed.go b/internal/packed/packed.go new file mode 100644 index 0000000..05d3470 --- /dev/null +++ b/internal/packed/packed.go @@ -0,0 +1,14 @@ +package packed + +import ( + _ "server/utility/myCasbin" + _ "server/utility/oss/aliyun" + + _ "github.com/gogf/gf/contrib/drivers/mysql/v2" + _ "github.com/gogf/gf/contrib/nosql/redis/v2" + "github.com/gogf/gf/frame/g" +) + +func init() { + g.I18n().SetLanguage("zh-CN") +} diff --git a/internal/service/admin.go b/internal/service/admin.go new file mode 100644 index 0000000..391f8b0 --- /dev/null +++ b/internal/service/admin.go @@ -0,0 +1,34 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "server/internal/model" +) + +type ( + IAdmin interface { + Login(ctx context.Context, in *model.AdminLoginIn) (out *model.AdminLoginOut, err error) + Info(ctx context.Context, in *model.AdminInfoIn) (out *model.AdminInfoOut, err error) + EditPass(ctx context.Context, in *model.AdminEditPassIn) (out *model.AdminEditPassOut, err error) + } +) + +var ( + localAdmin IAdmin +) + +func Admin() IAdmin { + if localAdmin == nil { + panic("implement not found for interface IAdmin, forgot register?") + } + return localAdmin +} + +func RegisterAdmin(i IAdmin) { + localAdmin = i +} diff --git a/internal/service/book.go b/internal/service/book.go new file mode 100644 index 0000000..16ffa3c --- /dev/null +++ b/internal/service/book.go @@ -0,0 +1,36 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "server/internal/model" +) + +type ( + IBook interface { + // List retrieves a paginated list of books + List(ctx context.Context, in *model.BookListIn) (out *model.BookListOut, err error) + Create(ctx context.Context, in *model.BookAddIn) (out *model.BookCRUDOut, err error) + Update(ctx context.Context, in *model.BookEditIn) (out *model.BookCRUDOut, err error) + Delete(ctx context.Context, in *model.BookDelIn) (out *model.BookCRUDOut, err error) + } +) + +var ( + localBook IBook +) + +func Book() IBook { + if localBook == nil { + panic("implement not found for interface IBook, forgot register?") + } + return localBook +} + +func RegisterBook(i IBook) { + localBook = i +} diff --git a/internal/service/category.go b/internal/service/category.go new file mode 100644 index 0000000..506fabb --- /dev/null +++ b/internal/service/category.go @@ -0,0 +1,36 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "server/internal/model" +) + +type ( + ICategory interface { + // List retrieves a paginated list of categories + List(ctx context.Context, in *model.CategoryListIn) (out *model.CategoryListOut, err error) + Create(ctx context.Context, in *model.CategoryAddIn) (out *model.CategoryCRUDOut, err error) + Update(ctx context.Context, in *model.CategoryEditIn) (out *model.CategoryCRUDOut, err error) + Delete(ctx context.Context, in *model.CategoryDelIn) (out *model.CategoryCRUDOut, err error) + } +) + +var ( + localCategory ICategory +) + +func Category() ICategory { + if localCategory == nil { + panic("implement not found for interface ICategory, forgot register?") + } + return localCategory +} + +func RegisterCategory(i ICategory) { + localCategory = i +} diff --git a/internal/service/chapter.go b/internal/service/chapter.go new file mode 100644 index 0000000..e0f9247 --- /dev/null +++ b/internal/service/chapter.go @@ -0,0 +1,36 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "server/internal/model" +) + +type ( + IChapter interface { + // List retrieves a paginated list of chapters + List(ctx context.Context, in *model.ChapterListIn) (out *model.ChapterListOut, err error) + Create(ctx context.Context, in *model.ChapterAddIn) (out *model.ChapterCRUDOut, err error) + Update(ctx context.Context, in *model.ChapterEditIn) (out *model.ChapterCRUDOut, err error) + Delete(ctx context.Context, in *model.ChapterDelIn) (out *model.ChapterCRUDOut, err error) + } +) + +var ( + localChapter IChapter +) + +func Chapter() IChapter { + if localChapter == nil { + panic("implement not found for interface IChapter, forgot register?") + } + return localChapter +} + +func RegisterChapter(i IChapter) { + localChapter = i +} diff --git a/internal/service/feedback.go b/internal/service/feedback.go new file mode 100644 index 0000000..b72b0f9 --- /dev/null +++ b/internal/service/feedback.go @@ -0,0 +1,35 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "server/internal/model" +) + +type ( + IFeedback interface { + // List retrieves a paginated list of feedbacks + List(ctx context.Context, in *model.FeedbackListIn) (out *model.FeedbackListOut, err error) + // Create adds a new feedback + Create(ctx context.Context, in *model.FeedbackAddIn) (out *model.FeedbackCRUDOut, err error) + } +) + +var ( + localFeedback IFeedback +) + +func Feedback() IFeedback { + if localFeedback == nil { + panic("implement not found for interface IFeedback, forgot register?") + } + return localFeedback +} + +func RegisterFeedback(i IFeedback) { + localFeedback = i +} diff --git a/internal/service/read_record.go b/internal/service/read_record.go new file mode 100644 index 0000000..cc5ba4b --- /dev/null +++ b/internal/service/read_record.go @@ -0,0 +1,37 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "server/internal/model" +) + +type ( + IReadRecord interface { + // List retrieves a paginated list of read records + List(ctx context.Context, in *model.ReadRecordListIn) (out *model.ReadRecordListOut, err error) + // Create adds a new read record + Create(ctx context.Context, in *model.ReadRecordAddIn) (out *model.ReadRecordCRUDOut, err error) + // Delete removes a read record by id + Delete(ctx context.Context, in *model.ReadRecordDelIn) (out *model.ReadRecordCRUDOut, err error) + } +) + +var ( + localReadRecord IReadRecord +) + +func ReadRecord() IReadRecord { + if localReadRecord == nil { + panic("implement not found for interface IReadRecord, forgot register?") + } + return localReadRecord +} + +func RegisterReadRecord(i IReadRecord) { + localReadRecord = i +} diff --git a/internal/service/tag.go b/internal/service/tag.go new file mode 100644 index 0000000..fef389a --- /dev/null +++ b/internal/service/tag.go @@ -0,0 +1,36 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "server/internal/model" +) + +type ( + ITag interface { + // List retrieves a paginated list of tags + List(ctx context.Context, in *model.TagListIn) (out *model.TagListOut, err error) + Create(ctx context.Context, in *model.TagAddIn) (out *model.TagCRUDOut, err error) + Update(ctx context.Context, in *model.TagEditIn) (out *model.TagCRUDOut, err error) + Delete(ctx context.Context, in *model.TagDelIn) (out *model.TagCRUDOut, err error) + } +) + +var ( + localTag ITag +) + +func Tag() ITag { + if localTag == nil { + panic("implement not found for interface ITag, forgot register?") + } + return localTag +} + +func RegisterTag(i ITag) { + localTag = i +} diff --git a/internal/service/user.go b/internal/service/user.go new file mode 100644 index 0000000..4f0a5f9 --- /dev/null +++ b/internal/service/user.go @@ -0,0 +1,37 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "server/internal/model" +) + +type ( + IUser interface { + Login(ctx context.Context, in *model.UserLoginIn) (out *model.UserLoginOut, err error) + Register(ctx context.Context, in *model.UserRegisterIn) (out *model.UserRegisterOut, err error) + Info(ctx context.Context, in *model.UserInfoIn) (out *model.UserInfoOut, err error) + Delete(ctx context.Context, in *model.UserDeleteIn) (out *model.UserDeleteOut, err error) + Code(ctx context.Context, in *model.UserCodeIn) (out *model.UserCodeOut, err error) + EditPass(ctx context.Context, in *model.UserEditPassIn) (out *model.UserEditPassOut, err error) + } +) + +var ( + localUser IUser +) + +func User() IUser { + if localUser == nil { + panic("implement not found for interface IUser, forgot register?") + } + return localUser +} + +func RegisterUser(i IUser) { + localUser = i +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..0b6e222 --- /dev/null +++ b/main.go @@ -0,0 +1,15 @@ +package main + +import ( + _ "server/internal/logic" + + "server/internal/cmd" + _ "server/internal/packed" + + "github.com/gogf/gf/v2/os/gctx" +) + +func main() { + + cmd.Main.Run(gctx.GetInitCtx()) +} diff --git a/manifest/config/rbac_model.conf b/manifest/config/rbac_model.conf new file mode 100644 index 0000000..872871d --- /dev/null +++ b/manifest/config/rbac_model.conf @@ -0,0 +1,14 @@ +[request_definition] +r = sub, obj, act + +[policy_definition] +p = sub, obj, act, desc + +[role_definition] +g = _, _ + +[policy_effect] +e = some(where (p.eft == allow)) + +[matchers] +m = g(r.sub, p.sub) && keyMatch2(r.obj, p.obj) && regexMatch(r.act, p.act) diff --git a/manifest/i18n/en/validation.toml b/manifest/i18n/en/validation.toml new file mode 100644 index 0000000..051d9ed --- /dev/null +++ b/manifest/i18n/en/validation.toml @@ -0,0 +1,45 @@ +"gf.gvalid.rule.required" = "The {field} field is required" +"gf.gvalid.rule.required-if" = "The {field} field is required" +"gf.gvalid.rule.required-unless" = "The {field} field is required" +"gf.gvalid.rule.required-with" = "The {field} field is required" +"gf.gvalid.rule.required-with-all" = "The {field} field is required" +"gf.gvalid.rule.required-without" = "The {field} field is required" +"gf.gvalid.rule.required-without-all" = "The {field} field is required" +"gf.gvalid.rule.date" = "The {field} value `{value}` is not a valid date" +"gf.gvalid.rule.datetime" = "The {field} value `{value}` is not a valid datetime" +"gf.gvalid.rule.date-format" = "The {field} value `{value}` does not match the format: {pattern}" +"gf.gvalid.rule.email" = "The {field} value `{value}` is not a valid email address" +"gf.gvalid.rule.phone" = "The {field} value `{value}` is not a valid phone number" +"gf.gvalid.rule.telephone" = "The {field} value `{value}` is not a valid telephone number" +"gf.gvalid.rule.passport" = "The {field} value `{value}` is not a valid passport format" +"gf.gvalid.rule.password" = "The {field} value `{value}` is not a valid password format" +"gf.gvalid.rule.password2" = "The {field} value `{value}` is not a valid password format" +"gf.gvalid.rule.password3" = "The {field} value `{value}` is not a valid password format" +"gf.gvalid.rule.postcode" = "The {field} value `{value}` is not a valid postcode format" +"gf.gvalid.rule.resident-id" = "The {field} value `{value}` is not a valid resident id number" +"gf.gvalid.rule.bank-card" = "The {field} value `{value}` is not a valid bank card number" +"gf.gvalid.rule.qq" = "The {field} value `{value}` is not a valid QQ number" +"gf.gvalid.rule.ip" = "The {field} value `{value}` is not a valid IP address" +"gf.gvalid.rule.ipv4" = "The {field} value `{value}` is not a valid IPv4 address" +"gf.gvalid.rule.ipv6" = "The {field} value `{value}` is not a valid IPv6 address" +"gf.gvalid.rule.mac" = "The {field} value `{value}` is not a valid MAC address" +"gf.gvalid.rule.url" = "The {field} value `{value}` is not a valid URL address" +"gf.gvalid.rule.domain" = "The {field} value `{value}` is not a valid domain format" +"gf.gvalid.rule.length" = "The {field} value `{value}` length must be between {min} and {max}" +"gf.gvalid.rule.min-length" = "The {field} value `{value}` length must be equal or greater than {min}" +"gf.gvalid.rule.max-length" = "The {field} value `{value}` length must be equal or lesser than {max}" +"gf.gvalid.rule.size" = "The {field} value `{value}` length must be {size}" +"gf.gvalid.rule.between" = "The {field} value `{value}` must be between {min} and {max}" +"gf.gvalid.rule.min" = "The {field} value `{value}` must be equal or greater than {min}" +"gf.gvalid.rule.max" = "The {field} value `{value}` must be equal or lesser than {max}" +"gf.gvalid.rule.json" = "The {field} value `{value}` is not a valid JSON string" +"gf.gvalid.rule.xml" = "The {field} value `{value}` is not a valid XML string" +"gf.gvalid.rule.array" = "The {field} value `{value}` is not an array" +"gf.gvalid.rule.integer" = "The {field} value `{value}` is not an integer" +"gf.gvalid.rule.boolean" = "The {field} value `{value}` field must be true or false" +"gf.gvalid.rule.same" = "The {field} value `{value}` must be the same as field {pattern}" +"gf.gvalid.rule.different" = "The {field} value `{value}` must be different from field {pattern}" +"gf.gvalid.rule.in" = "The {field} value `{value}` is not in acceptable range: {pattern}" +"gf.gvalid.rule.not-in" = "The {field} value `{value}` must not be in range: {pattern}" +"gf.gvalid.rule.regex" = "The {field} value `{value}` must be in regex of: {pattern}" +"gf.gvalid.rule.gf.gvalid.rule.__default__" = "The :attribute value `:value` is invalid" \ No newline at end of file diff --git a/manifest/i18n/zh-CN/validation.toml b/manifest/i18n/zh-CN/validation.toml new file mode 100644 index 0000000..d95bfc2 --- /dev/null +++ b/manifest/i18n/zh-CN/validation.toml @@ -0,0 +1,49 @@ +"gf.gvalid.rule.required" = "{field}字段不能为空" +"gf.gvalid.rule.required-if" = "{field}字段不能为空" +"gf.gvalid.rule.required-unless" = "{field}字段不能为空" +"gf.gvalid.rule.required-with" = "{field}字段不能为空" +"gf.gvalid.rule.required-with-all" = "{field}字段不能为空" +"gf.gvalid.rule.required-without" = "{field}字段不能为空" +"gf.gvalid.rule.required-without-all" = "{field}字段不能为空" +"gf.gvalid.rule.date" = "{field}字段值`{value}`日期格式不满足Y-m-d格式,例如: 2001-02-03" +"gf.gvalid.rule.datetime" = "{field}字段值`{value}`日期格式不满足Y-m-d H:i:s格式,例如: 2001-02-03 12:00:00" +"gf.gvalid.rule.date-format" = "{field}字段值`{value}`日期格式不满足{format}" +"gf.gvalid.rule.email" = "{field}字段值`{value}`邮箱地址格式不正确" +"gf.gvalid.rule.phone" = "{field}字段值`{value}`手机号码格式不正确" +"gf.gvalid.rule.phone-loose" = "{field}字段值`{value}`手机号码格式不正确" +"gf.gvalid.rule.telephone" = "{field}字段值`{value}`电话号码格式不正确" +"gf.gvalid.rule.passport" = "{field}字段值`{value}`账号格式不合法,必需以字母开头,只能包含字母、数字和下划线,长度在6~18之间" +"gf.gvalid.rule.password" = "{field}字段值`{value}`密码格式不合法,密码格式为任意6-18位的可见字符" +"gf.gvalid.rule.password2" = "{field}字段值`{value}`密码格式不合法,密码格式为任意6-18位的可见字符,必须包含大小写字母和数字" +"gf.gvalid.rule.password3" = "{field}字段值`{value}`密码格式不合法,密码格式为任意6-18位的可见字符,必须包含大小写字母、数字和特殊字符" +"gf.gvalid.rule.postcode" = "{field}字段值`{value}`邮政编码不正确" +"gf.gvalid.rule.resident-id" = "{field}字段值`{value}`身份证号码格式不正确" +"gf.gvalid.rule.bank-card" = "{field}字段值`{value}`银行卡号格式不正确" +"gf.gvalid.rule.qq" = "{field}字段值`{value}`QQ号码格式不正确" +"gf.gvalid.rule.ip" = "{field}字段值`{value}`IP地址格式不正确" +"gf.gvalid.rule.ipv4" = "{field}字段值`{value}`IPv4地址格式不正确" +"gf.gvalid.rule.ipv6" = "{field}字段值`{value}`IPv6地址格式不正确" +"gf.gvalid.rule.mac" = "{field}字段值`{value}`MAC地址格式不正确" +"gf.gvalid.rule.url" = "{field}字段值`{value}`URL地址格式不正确" +"gf.gvalid.rule.domain" = "{field}字段值`{value}`域名格式不正确" +"gf.gvalid.rule.length" = "{field}字段值`{value}`字段长度应当为{min}到{max}个字符" +"gf.gvalid.rule.min-length" = "{field}字段值`{value}`字段最小长度应当为{min}" +"gf.gvalid.rule.max-length" = "{field}字段值`{value}`字段最大长度应当为{max}" +"gf.gvalid.rule.size" = "{field}字段值`{value}`字段长度必须应当为{size}" +"gf.gvalid.rule.between" = "{field}字段值`{value}`字段大小应当为{min}到{max}" +"gf.gvalid.rule.min" = "{field}字段值`{value}`字段最小值应当为{min}" +"gf.gvalid.rule.max" = "{field}字段值`{value}`字段最大值应当为{max}" +"gf.gvalid.rule.json" = "{field}字段值`{value}`字段应当为JSON格式" +"gf.gvalid.rule.xml" = "{field}字段值`{value}`字段应当为XML格式" +"gf.gvalid.rule.array" = "{field}字段值`{value}`字段应当为数组" +"gf.gvalid.rule.integer" = "{field}字段值`{value}`字段应当为整数" +"gf.gvalid.rule.float" = "{field}字段值`{value}`字段应当为浮点数" +"gf.gvalid.rule.boolean" = "{field}字段值`{value}`字段应当为布尔值" +"gf.gvalid.rule.same" = "{field}字段值`{value}`字段值必须和{field}相同" +"gf.gvalid.rule.different" = "{field}字段值`{value}`字段值不能与{field}相同" +"gf.gvalid.rule.in" = "{field}字段值`{value}`字段值应当满足取值范围:{pattern}" +"gf.gvalid.rule.not-in" = "{field}字段值`{value}`字段值不应当满足取值范围:{pattern}" +"gf.gvalid.rule.regex" = "{field}字段值`{value}`字段值不满足规则:{pattern}" +"gf.gvalid.rule.__default__" = "{field}字段值`{value}`字段值不合法" +"CustomMessage" = "自定义错误" +"project id must between {min}, {max}" = "项目ID必须大于等于{min}并且要小于等于{max}" \ No newline at end of file diff --git a/utility/ecode/common.go b/utility/ecode/common.go new file mode 100644 index 0000000..cc0cb9d --- /dev/null +++ b/utility/ecode/common.go @@ -0,0 +1,17 @@ +package ecode + +var ( + OK = New(0, "success") + Sub = New(1, "") // 自定义错误信息 + Fail = New(2, "server_error") + InvalidOperation = New(3, "invalid_operation") + Params = New(4, "params_error") + Logout = New(5, "not_login") + Disabled = New(6, "account_disabled") + Denied = New(7, "permission_denied") + Expire = New(8, "token_expired") + Auth = New(1000, "auth_failed") + Password = New(1001, "password_incorrect") + EmailExist = New(1002, "email_exists") + NotFound = New(1003, "not_found") +) diff --git a/utility/ecode/ecode.go b/utility/ecode/ecode.go new file mode 100644 index 0000000..5606cb2 --- /dev/null +++ b/utility/ecode/ecode.go @@ -0,0 +1,90 @@ +package ecode + +import ( + "context" + "fmt" + "server/utility/i18n" + + "github.com/gogf/gf/v2/errors/gcode" +) + +type Error struct { + code int + message string + sub string + params []interface{} +} + +func New(code int, message string) Error { + return Error{ + code: code, + message: message, + } +} + +func (e Error) Params(params ...interface{}) Error { + e.params = append(e.params, params...) + return e +} + +func (e Error) Error() string { + return e.Message() +} + +func (e Error) Sub(sub string) Error { + e.sub = sub + return e +} + +func (e Error) Message() string { + if e.message != "" && len(e.params) > 0 { + e.message = fmt.Sprintf(e.message, e.params...) + } + if e.sub != "" { + if e.message != "" { + if len(e.params) > 0 { + e.message = fmt.Sprintf(e.message, e.params...) + } + return fmt.Sprintf("%s:%s", e.message, e.sub) + } + return e.sub + } + return e.message +} + +// MessageI18n 返回国际化消息 +func (e Error) MessageI18n(ctx context.Context) string { + // 如果有子消息,优先使用子消息的国际化 + if e.sub != "" { + return i18n.T(ctx, e.sub) + } + + // 否则使用主消息的国际化 + if e.message != "" { + // 尝试从国际化系统获取消息 + i18nMsg := i18n.T(ctx, e.message) + if i18nMsg != e.message { + // 如果找到了国际化消息,使用它 + if len(e.params) > 0 { + return fmt.Sprintf(i18nMsg, e.params...) + } + return i18nMsg + } + + // 如果没有找到国际化消息,使用原来的逻辑 + if len(e.params) > 0 { + return fmt.Sprintf(e.message, e.params...) + } + return e.message + } + + return "" +} + +func (e Error) Code() gcode.Code { + return gcode.New(e.code, e.Message(), "customer") +} + +func (e Error) Detail() interface{} { + return "customer" +} diff --git a/utility/encrypt/password.go b/utility/encrypt/password.go new file mode 100644 index 0000000..2353f24 --- /dev/null +++ b/utility/encrypt/password.go @@ -0,0 +1,44 @@ +package encrypt + +import "golang.org/x/crypto/bcrypt" + +// EncryptPassword 使用 bcrypt 算法对明文密码进行加密。 +// +// 参数: +// - password: 明文密码字符串。 +// +// 返回值: +// - 加密后的密码哈希(string)。 +// - 可能出现的错误(error)。 +// +// 示例: +// +// hashed, err := EncryptPassword("mySecret123") +// if err != nil { +// // 处理错误 +// } +func EncryptPassword(password string) (string, error) { + // 使用 bcrypt 的默认成本因子(10)进行加密 + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + if err != nil { + return "", err + } + return string(hashedPassword), nil +} + +// ComparePassword 比较明文密码与加密后的密码哈希是否匹配。 +// +// 参数: +// - hashedPassword: 已加密的密码哈希。 +// - password: 用户输入的明文密码。 +// +// 返回值: +// - 如果匹配返回 true,否则返回 false。 +// +// 示例: +// +// match := ComparePassword(storedHash, "userInput") +func ComparePassword(hashedPassword, password string) bool { + err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)) + return err == nil +} diff --git a/utility/i18n/i18n.go b/utility/i18n/i18n.go new file mode 100644 index 0000000..7e57144 --- /dev/null +++ b/utility/i18n/i18n.go @@ -0,0 +1,275 @@ +package i18n + +import ( + "context" + "fmt" + "strings" + + "github.com/gogf/gf/v2/frame/g" +) + +// 支持的语言列表 +var SupportedLanguages = []string{"zh-CN", "en-US"} + +// 默认语言 +const DefaultLanguage = "en-US" + +// 语言映射表 +var languageMap = map[string]map[string]string{ + "zh-CN": { + "hello": "你好,世界", + // 通用消息 + "success": "操作成功", + "server_error": "服务器内部错误", + "invalid_operation": "非法的操作请求", + "params_error": "请求参数错误", + "not_login": "用户未登录", + "account_disabled": "账户已被禁用", + "permission_denied": "没有权限执行该操作", + "token_expired": "token已过期", + "not_found": "资源不存在", + "forbidden": "禁止访问", + "unauthorized": "未授权访问", + "unknown_error": "未知错误", + + // 用户相关 + "auth_failed": "账户名或密码不正确", + "password_incorrect": "密码不正确", + "email_exists": "该邮箱已被注册", + "password_mismatch": "两次密码输入不一致", + "database_query_failed": "数据库查询失败", + "data_conversion_failed": "数据转换失败", + "token_generation_failed": "Token 生成失败", + "password_encryption_failed": "密码加密失败", + "registration_failed": "注册失败", + "user_not_found": "用户不存在或已被禁用", + "email_not_found": "未找到该邮箱注册账户", + + // 管理员相关 + "admin_not_found": "管理员不存在", + "admin_query_failed": "查询管理员信息失败", + "invalid_token_format": "无效的token格式", + "password_update_failed": "密码更新失败", + "token_parse_failed": "Token解析失败", + "invalid_token": "无效的Token", + + // 小说相关 + "book_query_failed": "小说查询失败", + "book_exists": "小说已存在", + "book_create_failed": "小说创建失败", + "book_not_found": "小说不存在", + "book_update_failed": "小说更新失败", + "book_delete_failed": "小说删除失败", + "chapter_not_found": "章节不存在", + "insufficient_points": "积分不足", + "chapter_locked": "章节已锁定,需要积分解锁", + + // 分类相关 + "category_query_failed": "分类查询失败", + "category_exists": "分类已存在", + "category_create_failed": "分类创建失败", + "category_not_found": "分类不存在", + "category_update_failed": "分类更新失败", + "category_delete_failed": "分类删除失败", + "category_type_invalid": "分类类型无效,只能为1(男频)或2(女频)", + + // 标签相关 + "tag_query_failed": "标签查询失败", + "tag_exists": "标签已存在", + "tag_create_failed": "标签创建失败", + "tag_not_found": "标签不存在", + "tag_update_failed": "标签更新失败", + "tag_delete_failed": "标签删除失败", + // 章节相关 + "chapter_query_failed": "章节查询失败", + "chapter_create_failed": "章节创建失败", + "chapter_update_failed": "章节更新失败", + "chapter_delete_failed": "章节删除失败", + // 反馈相关 + "feedback_create_failed": "反馈提交失败", + // 阅读记录相关 + "read_record_create_failed": "阅读记录创建失败", + "read_record_query_failed": "阅读记录查询失败", + "read_record_not_found": "阅读记录不存在", + "read_record_delete_failed": "阅读记录删除失败", + // 关注作者相关 + "user_follow_author_query_failed": "关注作者查询失败", + "user_follow_author_exists": "已关注该作者", + "user_follow_author_create_failed": "关注作者失败", + "user_follow_author_not_found": "关注记录不存在", + "user_follow_author_delete_failed": "取消关注失败", + }, + "en-US": { + "hello": "Hello World!", + // Common messages + "success": "Operation successful", + "server_error": "Internal server error", + "invalid_operation": "Invalid operation request", + "params_error": "Request parameter error", + "not_login": "User not logged in", + "account_disabled": "Account has been disabled", + "permission_denied": "No permission to perform this operation", + "token_expired": "Token has expired", + "not_found": "Resource not found", + "forbidden": "Access forbidden", + "unauthorized": "Unauthorized access", + "unknown_error": "Unknown error", + + // User related + "auth_failed": "Incorrect username or password", + "password_incorrect": "Incorrect password", + "email_exists": "This email has already been registered", + "password_mismatch": "Passwords do not match", + "database_query_failed": "Database query failed", + "data_conversion_failed": "Data conversion failed", + "token_generation_failed": "Token generation failed", + "password_encryption_failed": "Password encryption failed", + "registration_failed": "Registration failed", + "user_not_found": "User does not exist or has been disabled", + "email_not_found": "No registered account found for this email", + + // Admin related + "admin_not_found": "Administrator not found", + "admin_query_failed": "Failed to query administrator information", + "invalid_token_format": "Invalid token format", + "password_update_failed": "Password update failed", + "token_parse_failed": "Token parsing failed", + "invalid_token": "Invalid token", + + // Novel related + "book_query_failed": "Book query failed", + "book_exists": "Book already exists", + "book_create_failed": "Book creation failed", + "book_not_found": "Book not found", + "book_update_failed": "Book update failed", + "book_delete_failed": "Book deletion failed", + "chapter_not_found": "Chapter not found", + "insufficient_points": "Insufficient points", + "chapter_locked": "Chapter is locked, requires points to unlock", + + // Category related + "category_query_failed": "Category query failed", + "category_exists": "Category already exists", + "category_create_failed": "Category creation failed", + "category_not_found": "Category not found", + "category_update_failed": "Category update failed", + "category_delete_failed": "Category deletion failed", + "category_type_invalid": "Invalid category type, must be 1 (male) or 2 (female)", + + // Tag related + "tag_query_failed": "Tag query failed", + "tag_exists": "Tag already exists", + "tag_create_failed": "Tag creation failed", + "tag_not_found": "Tag not found", + "tag_update_failed": "Tag update failed", + "tag_delete_failed": "Tag deletion failed", + // Chapter related + "chapter_query_failed": "Chapter query failed", + "chapter_create_failed": "Chapter creation failed", + "chapter_update_failed": "Chapter update failed", + "chapter_delete_failed": "Chapter deletion failed", + // Feedback related + "feedback_create_failed": "Feedback creation failed", + // ReadRecord related + "read_record_create_failed": "Read record creation failed", + "read_record_query_failed": "Read record query failed", + "read_record_not_found": "Read record not found", + "read_record_delete_failed": "Read record deletion failed", + // UserFollowAuthor related + "user_follow_author_query_failed": "User follow author query failed", + "user_follow_author_exists": "Already followed this author", + "user_follow_author_create_failed": "User follow author creation failed", + "user_follow_author_not_found": "Follow record not found", + "user_follow_author_delete_failed": "Unfollow failed", + }, +} + +// GetLanguage 从请求头或查询参数获取语言设置 +func GetLanguage(ctx context.Context) string { + // 优先从请求头获取 + if r := g.RequestFromCtx(ctx); r != nil { + // 从 Accept-Language 头获取 + acceptLang := r.GetHeader("Accept-Language") + if acceptLang != "" { + lang := parseAcceptLanguage(acceptLang) + if isSupportedLanguage(lang) { + return lang + } + } + + // 从查询参数获取 + lang := r.Get("lang").String() + if isSupportedLanguage(lang) { + return lang + } + + // 从请求头获取自定义语言头 + lang = r.GetHeader("X-Language") + if isSupportedLanguage(lang) { + return lang + } + } + + return DefaultLanguage +} + +// T 翻译消息 +func T(ctx context.Context, key string) string { + lang := GetLanguage(ctx) + if messages, exists := languageMap[lang]; exists { + if message, exists := messages[key]; exists { + return message + } + } + + // 如果当前语言没有找到,尝试默认语言 + if lang != DefaultLanguage { + if messages, exists := languageMap[DefaultLanguage]; exists { + if message, exists := messages[key]; exists { + return message + } + } + } + + // 如果都没有找到,返回key本身 + return key +} + +// Tf 翻译消息并格式化 +func Tf(ctx context.Context, key string, args ...interface{}) string { + message := T(ctx, key) + if len(args) > 0 { + message = fmt.Sprintf(message, args...) + } + return message +} + +// isSupportedLanguage 检查是否为支持的语言 +func isSupportedLanguage(lang string) bool { + for _, supported := range SupportedLanguages { + if supported == lang { + return true + } + } + return false +} + +// parseAcceptLanguage 解析Accept-Language头 +func parseAcceptLanguage(acceptLang string) string { + // 简单的解析,取第一个语言代码 + parts := strings.Split(acceptLang, ",") + if len(parts) > 0 { + lang := strings.TrimSpace(parts[0]) + // 移除质量值 + if idx := strings.Index(lang, ";"); idx != -1 { + lang = lang[:idx] + } + return lang + } + return "" +} + +// GetSupportedLanguages 获取支持的语言列表 +func GetSupportedLanguages() []string { + return SupportedLanguages +} diff --git a/utility/jwt/jwt.go b/utility/jwt/jwt.go new file mode 100644 index 0000000..69915be --- /dev/null +++ b/utility/jwt/jwt.go @@ -0,0 +1,78 @@ +package jwt + +import ( + "errors" + "server/utility/ecode" + "strings" + "time" + + "github.com/golang-jwt/jwt/v5" + "github.com/google/uuid" +) + +var ( + secretKey = []byte("1a40c1d5b7a1b0f0fasdfaf835e0b24ca292a6") + issuer = "novel" +) + +type ( + TokenIn struct { + UserId int64 // 用户 ID + Role string // 权限标识 + } + TokenOut struct { + UserId int64 // 用户 ID + Role string // 权限标识 + JTI string // JWT 唯一标识 + } + + jwtClaims struct { + UserId int64 `json:"user_id"` // 用户 ID + Role string `json:"Role"` // 权限标识 + JTI string `json:"jti"` // 唯一标识 + jwt.RegisteredClaims + } +) + +func GenerateToken(in *TokenIn) (string, error) { + claims := jwtClaims{ + UserId: in.UserId, + Role: in.Role, + JTI: uuid.NewString(), + RegisteredClaims: jwt.RegisteredClaims{ + IssuedAt: jwt.NewNumericDate(time.Now()), + NotBefore: jwt.NewNumericDate(time.Now()), + Issuer: issuer, + }, + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + return token.SignedString(secretKey) +} + +func ParseToken(tokenString string) (*TokenOut, error) { + if strings.HasPrefix(tokenString, "Bearer ") { + tokenString = strings.TrimPrefix(tokenString, "Bearer ") + } + + token, err := jwt.ParseWithClaims(tokenString, &jwtClaims{}, func(token *jwt.Token) (interface{}, error) { + return secretKey, nil + }) + if err != nil { + if errors.Is(err, jwt.ErrTokenExpired) { + return nil, ecode.Expire.Sub("token_expired") + } + return nil, ecode.Fail.Sub("token_parse_failed") + } + + claims, ok := token.Claims.(*jwtClaims) + if !ok || !token.Valid { + return nil, ecode.InvalidOperation.Sub("invalid_token") + } + + return &TokenOut{ + UserId: claims.UserId, + Role: claims.Role, + JTI: claims.JTI, + }, nil +} diff --git a/utility/myCasbin/casbin.go b/utility/myCasbin/casbin.go new file mode 100644 index 0000000..71ccef5 --- /dev/null +++ b/utility/myCasbin/casbin.go @@ -0,0 +1,106 @@ +package myCasbin + +import ( + "context" + "github.com/casbin/casbin/v2" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/glog" + "github.com/hailaz/gf-casbin-adapter/v2" + "server/internal/consts" + "sync" +) + +type myCasbin struct { + *casbin.Enforcer +} + +var ( + instance *myCasbin + once sync.Once +) + +func init() { + ctx := context.Background() + once.Do(func() { + modelPath := g.Config().MustGet(ctx, "casbin.modelPath").String() + enforcer, err := casbin.NewEnforcer(modelPath, adapter.NewAdapter( + adapter.Options{ + GDB: g.DB(), + FieldName: &adapter.FieldName{PType: "p_type"}, + }, + )) + if err != nil { + glog.Errorf(ctx, "init casbin error: %v", err) + } + + enforcer.LoadPolicy() + + enforcer.AddGroupingPolicy(consts.UserRoleCode, consts.GuestRoleCode) + enforcer.AddGroupingPolicy(consts.AuthorRoleCode, consts.UserRoleCode) + enforcer.AddGroupingPolicy(consts.AdminRoleCode, consts.AuthorRoleCode) + // guest + { + + } + + // user + { + // book + // chapter + // feedback + // user + enforcer.AddPolicy("admin", "/user/info", "GET", "获取用户信息") + } + // author + { + // book + enforcer.AddPolicy("admin", "/book", "GET", "获取图书列表") + // chapter + + // category + enforcer.AddPolicy("admin", "/category", "GET", "获取分类列表") + } + + // admin + { + + // feedback + enforcer.AddPolicy("admin", "/feedback", "GET", "获取反馈列表") + // category + enforcer.AddPolicy("admin", "/category", "POST", "创建分类") + enforcer.AddPolicy("admin", "/category", "PUT", "更新分类") + enforcer.AddPolicy("admin", "/category", "DELETE", "删除分类") + // admin + enforcer.AddPolicy("admin", "/admin/info", "GET", "获取管理员用户信息") + } + instance = &myCasbin{Enforcer: enforcer} + + }) + glog.Infof(ctx, "init casbin success") +} + +func GetMyCasbin() *myCasbin { + if instance == nil { + panic("casbin not init") + } + return instance +} + +// HasPermission 判断给定的权限标识是否拥有访问指定 URL 和方法的权限。 +// +// 参数: +// - permission: 权限标识(如角色名或用户 ID) +// - url: 请求的路径(如 "/api/user/list") +// - method: HTTP 请求方法(如 "GET", "POST") +// +// 返回: +// - access: 如果有权限则为 true;否则为 false。 +// - 若校验过程中发生错误,将记录日志并返回 false。 +func (m *myCasbin) HasPermission(permission, url, method string) (access bool) { + enforce, err := m.Enforcer.Enforce(permission, url, method) + if err != nil { + glog.Errorf(context.Background(), "enforce error: %v", err) + return + } + return enforce +} diff --git a/utility/oss/aliyun/aliyun.go b/utility/oss/aliyun/aliyun.go new file mode 100644 index 0000000..0cc4cfc --- /dev/null +++ b/utility/oss/aliyun/aliyun.go @@ -0,0 +1,99 @@ +package aliyun + +import ( + "bytes" + "context" + "fmt" + "github.com/aliyun/aliyun-oss-go-sdk/oss" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/glog" + "github.com/gogf/gf/v2/util/grand" + "server/internal/model" + ioss "server/utility/oss" +) + +type aliyunClient struct { + bucketName string + key string + secret string + endpoint string +} + +// 初始化并注册 +func init() { + ctx := context.Background() + client := &aliyunClient{ + endpoint: g.Config().MustGet(ctx, "oss.aliyun.endpoint").String(), + key: g.Config().MustGet(ctx, "oss.aliyun.key").String(), + secret: g.Config().MustGet(ctx, "oss.aliyun.secret").String(), + bucketName: g.Config().MustGet(ctx, "oss.aliyun.bucket").String(), + } + ioss.Register("aliyun", client) + glog.Infof(ctx, "注册阿里云OSS成功") +} + +func (a *aliyunClient) client(ctx context.Context, endpoint, key, sercret string) (*oss.Client, error) { + client, err := oss.New(endpoint, key, sercret) + return client, err +} + +func (a *aliyunClient) bucket(ctx context.Context, client *oss.Client) (*oss.Bucket, error) { + bucket, err := client.Bucket(a.bucketName) + return bucket, err +} +func (a *aliyunClient) bytes(ctx context.Context, in *model.OssBytesInput) (*model.OssOutput, error) { + client, err := a.client(ctx, a.endpoint, a.key, a.secret) + if err != nil { + return nil, err + } + bucket, err := a.bucket(ctx, client) + if err != nil { + return nil, err + } + if in.Name == "" { + in.Name = grand.Digits(32) + } + err = bucket.PutObject(in.Name, bytes.NewReader(in.Bytes)) + if err != nil { + return nil, err + } + return &model.OssOutput{ + Url: fmt.Sprintf("https://%s.%s/%s", a.bucketName, a.endpoint, in.Name), + }, nil +} +func (a *aliyunClient) UploadFile(ctx context.Context, in *model.OssUploadFileInput) (out *model.OssOutput, err error) { + f, err := in.File.Open() + if err != nil { + return nil, err + } + defer f.Close() + body := make([]byte, in.File.Size) + _, err = f.Read(body) + if err != nil { + return nil, err + } + return a.bytes(ctx, &model.OssBytesInput{ + Name: in.Filename, + Bytes: body, + }) +} +func (a *aliyunClient) GetFileURL(ctx context.Context, in *model.OssGetFileInput) (out *model.OssOutput, err error) { + client, err := a.client(ctx, a.endpoint, a.key, a.secret) + if err != nil { + return nil, err + } + bucket, err := a.bucket(ctx, client) + if err != nil { + return nil, err + } + if in.Name == "" { + in.Name = grand.Digits(32) + } + err = bucket.PutObjectFromFile(in.Name, in.FilePath) + if err != nil { + return nil, err + } + return &model.OssOutput{ + Url: fmt.Sprintf("https://%s.%s/%s", a.bucketName, a.endpoint, in.Name), + }, nil +} diff --git a/utility/oss/oss.go b/utility/oss/oss.go new file mode 100644 index 0000000..33dc1ff --- /dev/null +++ b/utility/oss/oss.go @@ -0,0 +1,26 @@ +package oss + +import ( + "context" + "server/internal/model" +) + +// OssClient 是所有云存储平台要实现的统一接口 +type OssClient interface { + UploadFile(ctx context.Context, in *model.OssUploadFileInput) (out *model.OssOutput, err error) + GetFileURL(ctx context.Context, in *model.OssGetFileInput) (out *model.OssOutput, err error) +} + +// registry 存储各个平台的实现 +var clients = make(map[string]OssClient) + +// Register 用于注册平台实现 +func Register(name string, client OssClient) { + clients[name] = client +} + +// GetClient 获取指定平台的实现 +func GetClient(name string) (OssClient, bool) { + client, ok := clients[name] + return client, ok +}