commit 81926ce8a2fe79cff213b3409ac150289135b9c0 Author: Leon <147289645+LeoninCS@users.noreply.github.com> Date: Thu Dec 4 17:09:04 2025 +0800 init:搭建了整个项目的框架,初步写好了用户系统 diff --git a/README.md b/README.md new file mode 100644 index 0000000..30adb00 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# feedsystem_video_go +# 项目介绍 +一款基于go语言的视频feed流系统。 +# 文件介绍 +start.sh 为启动脚本 +postman.json 为postman的请求集合文件 +其余均为项目文件。 \ No newline at end of file diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..dabfed7 --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,34 @@ +package main + +import ( + "feedsystem_video_go/internal/config" + "feedsystem_video_go/internal/database" + "feedsystem_video_go/internal/router" + "log" +) + +func main() { + // Load config + log.Printf("Loading config from configs/config.yaml") + cfg, err := config.Load("configs/config.yaml") + if err != nil { + log.Fatalf("Failed to load config: %v", err) + } + // Connect database + log.Printf("Database config: %v", cfg.Database) + + db, err := database.NewDB(cfg.Database) + if err != nil { + log.Fatalf("Failed to connect database: %v", err) + } + if err := database.AutoMigrate(db); err != nil { + log.Fatalf("Failed to auto migrate database: %v", err) + } + defer database.CloseDB(db) + // Set router + r := router.SetRouter(db) + log.Printf("Server is running on port %s", cfg.Server.Port) + if err := r.Run(":" + cfg.Server.Port); err != nil { + log.Fatalf("Failed to run server: %v", err) + } +} diff --git a/configs/config.yaml b/configs/config.yaml new file mode 100644 index 0000000..0358a87 --- /dev/null +++ b/configs/config.yaml @@ -0,0 +1,9 @@ +server: + port: 8080 + +database: + host: localhost + port: 3306 + user: root + password: 123456 + dbname: feedsystem \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c75bc0a --- /dev/null +++ b/go.mod @@ -0,0 +1,48 @@ +module feedsystem_video_go + +go 1.24.5 + +require ( + github.com/gin-gonic/gin v1.11.0 + gopkg.in/yaml.v3 v3.0.1 + gorm.io/driver/mysql v1.6.0 + gorm.io/gorm v1.31.1 +) + +require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/bytedance/sonic v1.14.0 // indirect + github.com/bytedance/sonic/loader v0.3.0 // indirect + github.com/cloudwego/base64x v0.1.6 // indirect + github.com/gabriel-vasile/mimetype v1.4.8 // indirect + github.com/gin-contrib/sse v1.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.27.0 // indirect + github.com/go-sql-driver/mysql v1.8.1 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/goccy/go-yaml v1.18.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/quic-go/qpack v0.5.1 // indirect + github.com/quic-go/quic-go v0.54.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.3.0 // indirect + go.uber.org/mock v0.5.0 // indirect + golang.org/x/arch v0.20.0 // indirect + golang.org/x/crypto v0.40.0 // indirect + golang.org/x/mod v0.25.0 // indirect + golang.org/x/net v0.42.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/text v0.27.0 // indirect + golang.org/x/tools v0.34.0 // indirect + google.golang.org/protobuf v1.36.9 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..42484de --- /dev/null +++ b/go.sum @@ -0,0 +1,101 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ= +github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA= +github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA= +github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= +github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= +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/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= +github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= +github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk= +github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4= +github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= +github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mattn/go-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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +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/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= +github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= +github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg= +github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= +github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c= +golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg= +gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo= +gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg= +gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= diff --git a/internal/api/user.go b/internal/api/user.go new file mode 100644 index 0000000..560c6df --- /dev/null +++ b/internal/api/user.go @@ -0,0 +1,43 @@ +package api + +type CreateUserRequest struct { + Username string `json:"username"` + Password string `json:"password"` +} + +type CreateUserResponse struct { +} + +type RenameByIDRequest struct { + ID uint `json:"id"` + NewUsername string `json:"new_username"` +} + +type RenameByIDResponse struct { +} + +type FindByIDRequest struct { + ID uint `json:"id"` +} + +type FindByIDResponse struct { + ID uint `json:"id"` + Username string `json:"username"` +} + +type FindByUsernameRequest struct { + Username string `json:"username"` +} + +type FindByUsernameResponse struct { + ID uint `json:"id"` + Username string `json:"username"` +} + +type ChangePasswordRequest struct { + ID uint `json:"id"` + NewPassword string `json:"new_password"` +} + +type ChangePasswordResponse struct { +} diff --git a/internal/config/loadconfig.go b/internal/config/loadconfig.go new file mode 100644 index 0000000..d13e5a9 --- /dev/null +++ b/internal/config/loadconfig.go @@ -0,0 +1,38 @@ +package config + +import ( + "io/ioutil" + + "gopkg.in/yaml.v3" +) + +type Config struct { + Server ServerConfig `yaml:"server"` + Database DatabaseConfig `yaml:"database"` +} + +type ServerConfig struct { + Port string `yaml:"port"` +} + +type DatabaseConfig struct { + Host string `yaml:"host"` + Port string `yaml:"port"` + User string `yaml:"user"` + Password string `yaml:"password"` + DBName string `yaml:"dbname"` +} + +func Load(filename string) (Config, error) { + data, err := ioutil.ReadFile(filename) + if err != nil { + return Config{}, err + } + + var cfg Config + if err := yaml.Unmarshal(data, &cfg); err != nil { + return Config{}, err + } + + return cfg, nil +} diff --git a/internal/database/database.go b/internal/database/database.go new file mode 100644 index 0000000..b58edb8 --- /dev/null +++ b/internal/database/database.go @@ -0,0 +1,34 @@ +package database + +import ( + "feedsystem_video_go/internal/config" + "feedsystem_video_go/internal/model" + "fmt" + + "gorm.io/driver/mysql" + "gorm.io/gorm" +) + +func NewDB(dbcfg config.DatabaseConfig) (*gorm.DB, error) { + dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", + dbcfg.User, dbcfg.Password, dbcfg.Host, dbcfg.Port, dbcfg.DBName) + + db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) + if err != nil { + return nil, err + } + + return db, nil +} + +func AutoMigrate(db *gorm.DB) error { + return db.AutoMigrate(&model.User{}) +} + +func CloseDB(db *gorm.DB) error { + sqlDB, err := db.DB() + if err != nil { + return err + } + return sqlDB.Close() +} diff --git a/internal/handler/user.go b/internal/handler/user.go new file mode 100644 index 0000000..af625e0 --- /dev/null +++ b/internal/handler/user.go @@ -0,0 +1,86 @@ +package handler + +import ( + "feedsystem_video_go/internal/api" + "feedsystem_video_go/internal/model" + "feedsystem_video_go/internal/service" + + "github.com/gin-gonic/gin" +) + +type UserHandler struct { + userService *service.UserService +} + +func NewUserHandler(userService *service.UserService) *UserHandler { + return &UserHandler{userService: userService} +} +func (h *UserHandler) CreateUser(c *gin.Context) { + var req api.CreateUserRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(400, gin.H{"error": err.Error()}) + return + } + if err := h.userService.CreateUser(&model.User{ + Username: req.Username, + Password: req.Password, + }); err != nil { + c.JSON(500, gin.H{"error": err.Error()}) + return + } + c.JSON(200, gin.H{"message": "user created"}) +} + +func (h *UserHandler) RenameByID(c *gin.Context) { + var req api.RenameByIDRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(400, gin.H{"error": err.Error()}) + return + } + if err := h.userService.RenameByID(req.ID, req.NewUsername); err != nil { + c.JSON(500, gin.H{"error": err.Error()}) + return + } + c.JSON(200, gin.H{"message": "user renamed"}) +} + +func (h *UserHandler) ChangePassword(c *gin.Context) { + var req api.ChangePasswordRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(400, gin.H{"error": err.Error()}) + return + } + if err := h.userService.ChangePassword(req.ID, req.NewPassword); err != nil { + c.JSON(500, gin.H{"error": err.Error()}) + return + } + c.JSON(200, gin.H{"message": "password changed"}) +} + +func (h *UserHandler) FindByID(c *gin.Context) { + var req api.FindByIDRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(400, gin.H{"error": err.Error()}) + return + } + if user, err := h.userService.FindByID(req.ID); err != nil { + c.JSON(500, gin.H{"error": err.Error()}) + return + } else { + c.JSON(200, user) + } +} + +func (h *UserHandler) FindByUsername(c *gin.Context) { + var req api.FindByUsernameRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(400, gin.H{"error": err.Error()}) + return + } + if user, err := h.userService.FindByUsername(req.Username); err != nil { + c.JSON(500, gin.H{"error": err.Error()}) + return + } else { + c.JSON(200, user) + } +} diff --git a/internal/model/user.go b/internal/model/user.go new file mode 100644 index 0000000..901fb6f --- /dev/null +++ b/internal/model/user.go @@ -0,0 +1,7 @@ +package model + +type User struct { + ID uint `gorm:"primaryKey" json:"id"` + Username string `gorm:"unique" json:"username"` + Password string `json:"-"` +} diff --git a/internal/repository/user.go b/internal/repository/user.go new file mode 100644 index 0000000..ea568bd --- /dev/null +++ b/internal/repository/user.go @@ -0,0 +1,52 @@ +package repository + +import ( + "feedsystem_video_go/internal/model" + + "gorm.io/gorm" +) + +type UserRepository struct { + db *gorm.DB +} + +func NewUserRepository(db *gorm.DB) *UserRepository { + return &UserRepository{db: db} +} + +func (ur *UserRepository) CreateUser(user *model.User) error { + if err := ur.db.Create(user).Error; err != nil { + return err + } + return nil +} + +func (ur *UserRepository) RenameByID(id uint, newUsername string) error { + if err := ur.db.Model(&model.User{}).Where("id = ?", id).Update("username", newUsername).Error; err != nil { + return err + } + return nil +} + +func (ur *UserRepository) ChangePassword(id uint, newPassword string) error { + if err := ur.db.Model(&model.User{}).Where("id = ?", id).Update("password", newPassword).Error; err != nil { + return err + } + return nil +} + +func (ur *UserRepository) FindByID(id uint) (*model.User, error) { + var user model.User + if err := ur.db.First(&user, id).Error; err != nil { + return nil, err + } + return &user, nil +} + +func (ur *UserRepository) FindByUsername(username string) (*model.User, error) { + var user model.User + if err := ur.db.Where("username = ?", username).First(&user).Error; err != nil { + return nil, err + } + return &user, nil +} diff --git a/internal/router/router.go b/internal/router/router.go new file mode 100644 index 0000000..a6e99e6 --- /dev/null +++ b/internal/router/router.go @@ -0,0 +1,28 @@ +package router + +import ( + "feedsystem_video_go/internal/handler" + "feedsystem_video_go/internal/repository" + "feedsystem_video_go/internal/service" + + "github.com/gin-gonic/gin" + "gorm.io/gorm" +) + +func SetRouter(db *gorm.DB) *gin.Engine { + r := gin.Default() + + userRepository := repository.NewUserRepository(db) + userService := service.NewUserService(userRepository) + userHandler := handler.NewUserHandler(userService) + userGroup := r.Group("/user") + { + userGroup.POST("/register", userHandler.CreateUser) + userGroup.POST("/rename", userHandler.RenameByID) + userGroup.POST("/changePassword", userHandler.ChangePassword) + userGroup.POST("/findByID", userHandler.FindByID) + userGroup.POST("/findByUsername", userHandler.FindByUsername) + } + + return r +} diff --git a/internal/service/user.go b/internal/service/user.go new file mode 100644 index 0000000..40dd5cd --- /dev/null +++ b/internal/service/user.go @@ -0,0 +1,51 @@ +package service + +import ( + "feedsystem_video_go/internal/model" + "feedsystem_video_go/internal/repository" +) + +type UserService struct { + userRepository *repository.UserRepository +} + +func NewUserService(userRepository *repository.UserRepository) *UserService { + return &UserService{userRepository: userRepository} +} + +func (us *UserService) CreateUser(user *model.User) error { + if err := us.userRepository.CreateUser(user); err != nil { + return err + } + return nil +} + +func (us *UserService) RenameByID(id uint, newUsername string) error { + if err := us.userRepository.RenameByID(id, newUsername); err != nil { + return err + } + return nil +} + +func (us *UserService) ChangePassword(id uint, newPassword string) error { + if err := us.userRepository.ChangePassword(id, newPassword); err != nil { + return err + } + return nil +} + +func (us *UserService) FindByID(id uint) (*model.User, error) { + if user, err := us.userRepository.FindByID(id); err != nil { + return nil, err + } else { + return user, nil + } +} + +func (us *UserService) FindByUsername(username string) (*model.User, error) { + if user, err := us.userRepository.FindByUsername(username); err != nil { + return nil, err + } else { + return user, nil + } +} diff --git a/postman.json b/postman.json new file mode 100644 index 0000000..55d2cc7 --- /dev/null +++ b/postman.json @@ -0,0 +1,106 @@ +{ + "info": { + "name": "FeedSystem User API", + "_postman_id": "d5b2888b-1a7d-4c38-9f6b-13ab3e8ffb51", + "description": "Basic user endpoints for feedsystem_video_go", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Register User", + "request": { + "method": "POST", + "header": [ + { "key": "Content-Type", "value": "application/json" } + ], + "body": { + "mode": "raw", + "raw": "{\n \"username\": \"alice\",\n \"password\": \"pass123\"\n}" + }, + "url": { + "raw": "{{host}}/user/register", + "host": ["{{host}}"], + "path": ["user", "register"] + } + } + }, + { + "name": "Rename User", + "request": { + "method": "POST", + "header": [ + { "key": "Content-Type", "value": "application/json" } + ], + "body": { + "mode": "raw", + "raw": "{\n \"id\": 1,\n \"new_username\": \"alice_new\"\n}" + }, + "url": { + "raw": "{{host}}/user/rename", + "host": ["{{host}}"], + "path": ["user", "rename"] + } + } + }, + { + "name": "Change Password", + "request": { + "method": "POST", + "header": [ + { "key": "Content-Type", "value": "application/json" } + ], + "body": { + "mode": "raw", + "raw": "{\n \"id\": 1,\n \"new_password\": \"newpass456\"\n}" + }, + "url": { + "raw": "{{host}}/user/changePassword", + "host": ["{{host}}"], + "path": ["user", "changePassword"] + } + } + }, + { + "name": "Find User By ID", + "request": { + "method": "POST", + "header": [ + { "key": "Content-Type", "value": "application/json" } + ], + "body": { + "mode": "raw", + "raw": "{\n \"id\": 1\n}" + }, + "url": { + "raw": "{{host}}/user/findByID", + "host": ["{{host}}"], + "path": ["user", "findByID"] + } + } + }, + { + "name": "Find User By Username", + "request": { + "method": "POST", + "header": [ + { "key": "Content-Type", "value": "application/json" } + ], + "body": { + "mode": "raw", + "raw": "{\n \"username\": \"alice_new\"\n}" + }, + "url": { + "raw": "{{host}}/user/findByUsername", + "host": ["{{host}}"], + "path": ["user", "findByUsername"] + } + } + } + ], + "variable": [ + { + "key": "host", + "value": "http://localhost:8080" + } + ] +} diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..ec1c72f --- /dev/null +++ b/start.sh @@ -0,0 +1,2 @@ +# 启动服务器 +go run cmd/main.go \ No newline at end of file