diff --git a/go_web_1 b/go_web_1 new file mode 160000 index 0000000..c69c0a7 --- /dev/null +++ b/go_web_1 @@ -0,0 +1 @@ +Subproject commit c69c0a7690fdc5c1a36fb2e6d7f8aeb2ad875d50 diff --git a/roboko12/Dockerfile b/roboko12/Dockerfile new file mode 100644 index 0000000..aa86848 --- /dev/null +++ b/roboko12/Dockerfile @@ -0,0 +1,28 @@ +FROM golang:alpine AS builder + +# 为我们的镜像设置必要的环境变量 +ENV GO111MODULE=on \ + GOPROXY=https://goproxy.cn,direct \ + CGO_ENABLED=0 \ + GOOS=linux \ + GOARCH=amd64 + +# 移动到工作目录:/build +WORKDIR /build + +# 将代码复制到容器中 +COPY . . + +# 将我们的代码编译成二进制可执行文件 app +RUN go build -o app . + +################### +# 接下来创建一个小镜像 +################### +FROM scratch + +# 从builder镜像中把/dist/app 拷贝到当前目录 +COPY --from=builder /build/app / + +# 需要运行的命令 +ENTRYPOINT ["/app"] diff --git a/roboko12/__debug_bin1067692169.exe b/roboko12/__debug_bin1067692169.exe new file mode 100644 index 0000000..73c3848 Binary files /dev/null and b/roboko12/__debug_bin1067692169.exe differ diff --git a/roboko12/__debug_bin1222785051.exe b/roboko12/__debug_bin1222785051.exe new file mode 100644 index 0000000..a6d7206 Binary files /dev/null and b/roboko12/__debug_bin1222785051.exe differ diff --git a/roboko12/__debug_bin197326567.exe b/roboko12/__debug_bin197326567.exe new file mode 100644 index 0000000..7ab223f Binary files /dev/null and b/roboko12/__debug_bin197326567.exe differ diff --git a/roboko12/__debug_bin630280278.exe b/roboko12/__debug_bin630280278.exe new file mode 100644 index 0000000..63e9613 Binary files /dev/null and b/roboko12/__debug_bin630280278.exe differ diff --git a/roboko12/__debug_bin708761844.exe b/roboko12/__debug_bin708761844.exe new file mode 100644 index 0000000..63e9613 Binary files /dev/null and b/roboko12/__debug_bin708761844.exe differ diff --git a/roboko12/go.mod b/roboko12/go.mod new file mode 100644 index 0000000..9e949f0 --- /dev/null +++ b/roboko12/go.mod @@ -0,0 +1,43 @@ +module sample-app + +go 1.23.1 + +require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/bytedance/sonic v1.12.3 // indirect + github.com/bytedance/sonic/loader v0.2.0 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.5 // indirect + github.com/gin-contrib/sessions v1.0.1 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.10.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.22.1 // indirect + github.com/go-sql-driver/mysql v1.8.1 // indirect + github.com/goccy/go-json v0.10.3 // indirect + github.com/gorilla/context v1.1.2 // indirect + github.com/gorilla/securecookie v1.1.2 // indirect + github.com/gorilla/sessions v1.2.2 // 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.2.8 // 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-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + golang.org/x/arch v0.10.0 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/driver/mysql v1.5.7 // indirect + gorm.io/gorm v1.25.12 // indirect +) diff --git a/roboko12/go.sum b/roboko12/go.sum new file mode 100644 index 0000000..f9ab734 --- /dev/null +++ b/roboko12/go.sum @@ -0,0 +1,127 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= +github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= +github.com/bytedance/sonic v1.12.3 h1:W2MGa7RCU1QTeYRTPE3+88mVC0yXmsRQRChiyVocVjU= +github.com/bytedance/sonic v1.12.3/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= +github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= +github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= +github.com/gin-contrib/sessions v1.0.1 h1:3hsJyNs7v7N8OtelFmYXFrulAf6zSR7nW/putcPEHxI= +github.com/gin-contrib/sessions v1.0.1/go.mod h1:ouxSFM24/OgIud5MJYQJLpy6AwxQ5EYO9yLhbtObGkM= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +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.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= +github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA= +github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +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-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o= +github.com/gorilla/context v1.1.2/go.mod h1:KDPwT9i/MeWHiLl90fuTgrt4/wPcv75vFAZLaOOcbxM= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= +github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= +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.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +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/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/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.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +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/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.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.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +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.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= +golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/arch v0.10.0 h1:S3huipmSclq3PJMNe76NGwkBR504WFkQ5dhzWzP8ZW8= +golang.org/x/arch v0.10.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +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.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= +gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/roboko12/main.go b/roboko12/main.go new file mode 100644 index 0000000..2f71bc0 --- /dev/null +++ b/roboko12/main.go @@ -0,0 +1,189 @@ +package main + +import ( + "log" + "strconv" + "time" + + "github.com/gin-contrib/sessions" + "github.com/gin-contrib/sessions/cookie" + "github.com/gin-gonic/gin" + "gorm.io/driver/mysql" + "gorm.io/gorm" +) + +// 用户结构体 +type User struct { + gorm.Model + Username string `gorm:"unique;not null"` + Password string `gorm:"not null"` + IsManager bool +} + +type KeyWord struct { + Keyword string +} + +// 问题结构体 +type Question struct { + gorm.Model + Title string + Content string + UserID uint + Answers []Answer `gorm:"foreignKey:QuestionID"` + IsDeleted bool + Deleted_Time time.Time +} + +type AgreeOrNot struct { + AgreeNum uint + DisagreeNum uint +} + +// 答案中的评论结构体 +type Comment struct { + gorm.Model + AgreeOrNot + Content string + UserID uint + AnswerID uint +} + +// 回复评论结构体 +type ReplyComment struct { + gorm.Model + CommentUserID uint + CommentID uint + ReplyCommentID uint + ReplyUserID uint +} + +// 答案结构体 +type Answer struct { + gorm.Model + AgreeOrNot + Content string + UserID uint + QuestionID uint + IsDeleted bool + // 评论 + Comments []Comment `gorm:"foreignKey:AnswerID"` +} + +var db *gorm.DB + +const max_question_num = 30 + +var resultCh chan Question = make(chan Question, max_question_num) + +func main() { + var err error + // 使用mysql.Open创建Dialector实例 + dialector := mysql.Open("root:123Qbz123@tcp(localhost:3306)/go_web_1?charset=utf8mb4&parseTime=True&loc=Local") + // 将Dialector实例传递给gorm.Open + db, err = gorm.Open(dialector, &gorm.Config{}) + if err != nil { + log.Fatal("数据库连接失败:", err) + } + db.AutoMigrate(&User{}, &Question{}, &Answer{}, &Comment{}, &ReplyComment{}) + + r := gin.Default() + + // 设置会话 + store := cookie.NewStore([]byte("secret")) + r.Use(sessions.Sessions("mysession", store)) + + v_post := r.Group("/") + { + //注册 + v_post.POST("register", Register) + //登录 + v_post.POST("login", Login) + // 提出问题 + v_post.POST("questions", CreateQuestion) + // 回答问题 + v_post.POST("questions/:question_id/answers", CreateAnswer) + // 评论答案,需要查询参数,传入答案id和所属问题id + v_post.POST("questions/answers/comments", CreateCommentToAnswer) + //回复其他评论,需要传入查询参数,传入其他评论id和所属答案id + v_post.POST("questions/answers/comments/comments", CreateReplyToComment) + + } + + v_get := r.Group("/") + { + // 查看某个用户提出的问题 + v_get.GET(":user_id/questions", GetQuestions) + // 查看某问题的答案 + v_get.GET("questions/:question_id/answers", GetAnswers) + // 查看被逻辑删除删除的问题 + v_get.GET("deleted_questions", GetDeletedQuestions) + //按关键词搜索问题 + v_get.GET("questions/search", SearchQuestionsByKeyword) + //查看对自己评论的回复 + v_get.GET("questions/answers/comments/comments", GetReplysToSelf) + + } + + v_put := r.Group("/") + { + //申请管理员权限 + v_put.PUT("users", ApplyManager) + // 更新问题内容 + v_put.PUT("questions/:id", UpdateQuestionContent) + // 恢复被逻辑删除的问题 + v_put.PUT("deleted_questions/:id", RestoreQuestion) + // 赞同答案 + v_put.PUT("questions/answers/agree", AgreeAnswer) + // 反对答案 + v_put.PUT("questions/answers/disagree", DisagreeAnswer) + //恢复被删除的答案,需要传入查询参数,传入答案id和所属问题id + v_put.PUT("questions/answers/restore", RestoreAnswer) + //恢复对答案的评论,需要传入查询参数,传入评论id和所属答案id + v_put.PUT("questions/answers/comments/restore", RestoreCommentToAnswer) + } + + v_delete := r.Group("/") + { + // 逻辑删除问题 + v_delete.DELETE("questions/:id", DeleteQuestion) + // 永久删除问题 + v_delete.DELETE("deleted_questions/:id", DeleteQuestionForever) + // 永久删除答案 + v_delete.DELETE("questions/answers", DeleteAnswerForever) + //逻辑删除答案,需要传入查询参数,传入答案id和所属问题id + v_delete.DELETE("questions/deleted_answers", DeleteAnswer) + //软删除评论,需要传入查询参数,传入评论id和所属答案id + v_delete.DELETE("questions/answers/comments", DeleteCommentToAnswer) + //永久删除评论,需要传入查询参数,传入评论id和所属答案id + v_delete.DELETE("questions/answers/deleted_comments", DeleteCommentForever) + } + + //统计每个被删除的删除天数,超过15天则永久删除 + go func() { + flag := true + for flag { + time.Sleep(time.Second * 30) // 添加延迟 + deleted_questions.mux.Lock() + for _, q := range deleted_questions.deleted { + if q.IsDeleted && time.Since(q.Deleted_Time) > time.Second*10 { + resultCh <- q + db.Unscoped().Delete(&q) + } + } + deleted_questions.mux.Unlock() + } + }() + + // 收集结果 + go func() { + for { + select { + case q := <-resultCh: + delete(deleted_questions.deleted, strconv.FormatUint(uint64(q.ID), 10)) + } + } + }() + + r.Run(":8080") +} diff --git a/roboko12/readme.doc/ou1q07ujnw.apifox.cn b/roboko12/readme.doc/ou1q07ujnw.apifox.cn new file mode 100644 index 0000000..e69de29 diff --git a/roboko12/route.go b/roboko12/route.go new file mode 100644 index 0000000..d144520 --- /dev/null +++ b/roboko12/route.go @@ -0,0 +1,863 @@ +package main + +import ( + "database/sql" + "fmt" + "log" + "net/http" + "strconv" + "sync" + "time" + + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + _ "github.com/go-sql-driver/mysql" +) + +type Deleted_Questions struct { + deleted map[string]Question + mux sync.Mutex +} + +var deleted_questions Deleted_Questions = Deleted_Questions{deleted: make(map[string]Question)} + +// 检查是否登录 +func CheckLogin(c *gin.Context) interface{} { + session := sessions.Default(c) + userID := session.Get("user_id") + if userID == nil { + return nil + } + return userID +} + +// 初始化答案的属性,只初始化了部分属性,意味着诸如创建时间的属性不会被初始化 +// 只在删除答案中可以使用 + +func (answer *Answer) Init(c *gin.Context, user_id uint) { + + answer_id := c.Query("answer_id") + question_id := c.Query("question_id") + var err error + var int_answer_id int + var int_question_id int + if int_answer_id, err = strconv.Atoi(answer_id); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + if int_question_id, err = strconv.Atoi(question_id); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + answer.UserID = user_id + answer.ID = uint(int_answer_id) + answer.QuestionID = uint(int_question_id) +} + +// 初始化评论的属性 +func (comment *Comment) Init(c *gin.Context) { + + comment_id := c.Query("comment_id") + answer_id := c.Query("answer_id") + var int_comment_id int + var int_answer_id int + var err error + if int_comment_id, err = strconv.Atoi(comment_id); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + if int_answer_id, err = strconv.Atoi(answer_id); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + comment.AnswerID = uint(int_answer_id) + comment.ID = uint(int_comment_id) + +} + +// 申请管理员权限 +func ApplyManager(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + id := userID.(uint) + var answer Answer + var answer_sum int64 + var totalAgreeCount int64 + if err := db.Model(&answer).Where("user_id =?", id).Count(&answer_sum).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + if answer_sum < 1 { + c.JSON(http.StatusBadRequest, gin.H{"error": "您的回答数量不足"}) + return + } + if err := db.Model(&Answer{}).Where("user_id =?", id).Select("SUM(agree_num)").Scan(&totalAgreeCount).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + if totalAgreeCount < 1000 { + c.JSON(http.StatusBadRequest, gin.H{"error": "您的赞同数量不足"}) + return + } + // 更新用户为管理员 + if err := db.Model(&User{}).Where("id =?", id).Update("is_manager", true).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"message": "申请管理员成功"}) +} + +// 检查用户是否是管理员 +func CheckManager(user_id uint) bool { + var user User + if err := db.Where("id =?", user_id).First(&user).Error; err != nil { + return false + } + return user.IsManager + +} + +// 注册 +func Register(c *gin.Context) { + var user User + user.IsManager = false + if err := c.ShouldBindJSON(&user); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + fmt.Println("error:", err.Error()) + return + } + if err := db.Create(&user).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusCreated, gin.H{"message": "用户注册成功"}) +} + +// 登录 +func Login(c *gin.Context) { + var user User + if err := c.ShouldBindJSON(&user); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + var storedUser User + if err := db.Where("username =?", user.Username).First(&storedUser).Error; err != nil { + if err == sql.ErrNoRows { + c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"}) + return + } + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + if storedUser.Password != user.Password { + c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"}) + return + } + session := sessions.Default(c) + session.Set("user_id", storedUser.ID) + session.Save() + c.JSON(http.StatusOK, gin.H{"message": "登录成功"}) +} + +// 创建问题 +func CreateQuestion(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + var question Question + if err := c.ShouldBindJSON(&question); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + question.UserID = userID.(uint) + question.Answers = []Answer{} + question.IsDeleted = false + + //将被删除时间设为一个未来的时间点,代表该问题未被删除 + question.Deleted_Time = time.Date(3000, 1, 1, 1, 1, 1, 1, time.UTC) + if err := db.Create(&question).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusCreated, gin.H{"message": "问题提出成功", "question": question}) +} + +// 创建答案 +func CreateAnswer(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + var answer Answer + var err error + var question_id int + if question_id, err = strconv.Atoi(c.Param("question_id")); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + answer.QuestionID = uint(question_id) + if err := c.ShouldBindJSON(&answer); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + var question Question + if err := db.Where("id =?", answer.QuestionID).First(&question).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + if question.IsDeleted { + c.JSON(http.StatusBadRequest, gin.H{"error": "该问题已被删除"}) + return + } + + // 初始化答案的属性 + answer.UserID = userID.(uint) + answer.CreatedAt = time.Now() + answer.AgreeNum = 0 + answer.IsDeleted = false + answer.DisagreeNum = 0 + answer.Comments = []Comment{} + + if err := db.Create(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"message": "回答创建失败", "error": err.Error()}) + return + } + + //将回答添加到问题中 + question.Answers = append(question.Answers, answer) + if err := db.Save(&question).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusCreated, gin.H{"message": "回答创建成功", "answer": answer}) +} + +// 赞同答案 +func AgreeAnswer(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + + var answer Answer + answer.Init(c, userID.(uint)) + + if err := db.Where("id =?", answer.ID).First(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + answer.AgreeNum++ + if err := db.Save(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"message": "赞同成功"}) +} + +// 反对答案 +func DisagreeAnswer(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + + var answer Answer + answer.Init(c, userID.(uint)) + + if err := db.Where("id =?", answer.ID).First(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + answer.DisagreeNum++ + if err := db.Save(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"message": "反对成功"}) +} + +// 对答案评论 +func CreateComment(c *gin.Context) { + UserID := CheckLogin(c) + if UserID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + +} + +//对别人的评论进行评论 + +// 查看某用户提出的问题 +func GetQuestions(c *gin.Context) { + var questions []Question + user_id := c.Param("user_id") + sort_way := c.DefaultQuery("sort_way", "created_at desc") + if err := db.Where("is_deleted = false AND user_id = ?", user_id).Order(sort_way).Find(&questions).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"questions": questions}) +} + +// 查看某问题答案 +func GetAnswers(c *gin.Context) { + var answers []Answer + question_id := c.Param("question_id") + sort_way := c.DefaultQuery("sort_way", "agree_num desc") + if err := db.Where("question_id =?", question_id).Find(&answers).Order(sort_way).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"answers": answers}) +} + +func GetDeletedQuestions(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + var questions []Question + if err := db.Where("is_deleted = true").Find(&questions).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"questions": questions}) +} + +// 更新问题内容 +func UpdateQuestionContent(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + id := c.Param("id") + var question Question + if err := db.Where("id =?", id).First(&question).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + if err := c.ShouldBindJSON(&question); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + if err := db.Save(&question).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"message": "问题修改成功", "question": question}) +} + +// 恢复被逻辑删除的问题 +func RestoreQuestion(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + id := c.Param("id") + var question Question + if err := db.Where("id =?", id).First(&question).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + question.IsDeleted = false + db.Unscoped().Model(&question).Update("deleted_at", nil) + if err := db.Save(&question).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"message": "问题恢复成功", "question": question}) +} + +// 逻辑删除问题 +func DeleteQuestion(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + id := c.Param("id") + delete_forever := c.Query("delete_forever") + var question Question + if err := db.Where("id =?", id).First(&question).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + if question.UserID != userID.(uint) { + c.JSON(http.StatusUnauthorized, gin.H{"error": "您没有权限删除该问题"}) + return + } + + if delete_forever == "false" { + //逻辑删除问题的所有答案 + for _, answer := range question.Answers { + answer.delete_answer(&question) + } + //保存被删除的问题到map中 + deleted_questions.deleted[id] = question + question.Deleted_Time = time.Now() + question.IsDeleted = true + db.Delete(&question) + if err := db.Save(&question).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"message": "问题删除成功, 该问题已被逻辑删除,可自行选择是否永久删除"}) + } + if delete_forever == "true" { + //永久删除问题的所有答案 + for _, answer := range question.Answers { + if answer.delete_answer_forever(&question) { + c.JSON(http.StatusOK, gin.H{"message": "答案删除成功"}) + return + } + c.JSON(http.StatusInternalServerError, gin.H{"error": "答案删除失败"}) + } + if err := db.Unscoped().Delete(&question).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"message": "问题删除成功, 该问题已被永久删除"}) + return + } + +} + +// 永久删除问题 +func DeleteQuestionForever(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + + user_id := userID.(uint) + + id := c.Param("id") + var question Question + if err := db.Where("id =?", id).Unscoped().First(&question).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + if question.UserID != user_id && !CheckManager(user_id) { + c.JSON(http.StatusUnauthorized, gin.H{"error": "您没有权限删除该问题"}) + return + } + + //删除问题的所有答案 + for _, answer := range question.Answers { + if answer.delete_answer_forever(&question) { + c.JSON(http.StatusOK, gin.H{"message": "答案删除成功"}) + return + } + c.JSON(http.StatusInternalServerError, gin.H{"error": "答案删除失败"}) + } + + //然后删除问题 + if err := db.Unscoped().Delete(&question).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"message": "问题删除成功"}) + +} + +// 永久删除答案 +func (answer *Answer) delete_answer_forever(question *Question) bool { + //将答案从所属问题中删除 + len := len(question.Answers) + question.Answers = append(question.Answers[:len], question.Answers[len:]...) + + //删除所属的所有评论 + + if err := db.Where("id =?", answer.ID).First(&answer).Error; err != nil { + log.Output(2, err.Error()) + return false + } + if err := db.Unscoped().Delete(&answer).Error; err != nil { + log.Output(2, err.Error()) + return false + } + return true +} + +func DeleteAnswerForever(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + + var answer Answer + answer.Init(c, userID.(uint)) + + if err := db.Where("id =?", answer.ID).First(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + if answer.UserID != userID.(uint) && !CheckManager(userID.(uint)) { + c.JSON(http.StatusUnauthorized, gin.H{"error": "您没有权限删除该答案"}) + return + } + + var question Question + + if err := db.Where("id =?", answer.QuestionID).First(&question).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + if answer.delete_answer_forever(&question) { + c.JSON(http.StatusOK, gin.H{"message": "答案删除成功"}) + return + } + c.JSON(http.StatusInternalServerError, gin.H{"error": "答案删除失败"}) +} + +//逻辑删除答案 + +func (answer *Answer) delete_answer(question *Question) bool { + answer.IsDeleted = true + len := len(question.Answers) + question.Answers = append(question.Answers[:len], question.Answers[len:]...) + db.Delete(&answer) + //逻辑删除答案的所有评论 + + if err := db.Save(&answer).Error; err != nil { + log.Output(2, err.Error()) + return false + } + return true +} + +func DeleteAnswer(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + + var answer Answer + answer_id := c.Query("answer_id") + if err := db.Where("id =?", answer_id).First(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + if answer.UserID != userID.(uint) && !CheckManager(userID.(uint)) { + c.JSON(http.StatusUnauthorized, gin.H{"error": "您没有权限删除该问题"}) + return + } + var question Question + + if err := db.Where("id =?", answer.QuestionID).First(&question).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + if answer.delete_answer(&question) { + c.JSON(http.StatusOK, gin.H{"message": "答案删除成功,可以自行选择是否永久删除"}) + return + } + c.JSON(http.StatusInternalServerError, gin.H{"error": "答案删除失败"}) +} + +// 恢复答案 +func RestoreAnswer(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + + var answer Answer + answer.Init(c, userID.(uint)) + + answer.IsDeleted = false + db.Unscoped().Model(&answer).Update("deleted_at", nil) + db.Unscoped().Model(&answer).Update("IsDeleted", false) + + var question Question + + if err := db.Where("id =?", answer.QuestionID).First(&question).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + question.Answers = append(question.Answers, answer) + + c.JSON(http.StatusOK, gin.H{"message": "答案恢复成功"}) +} + +// 评论答案 +func CreateCommentToAnswer(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + + var answer Answer + answer_id := c.Query("answer_id") + //查找答案 + if err := db.Where("id =?", answer_id).First(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + var comment Comment + if c.ShouldBindJSON(&comment) != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数有误"}) + return + } + + comment.AnswerID = answer.ID + comment.UserID = userID.(uint) + comment.AgreeNum = 0 + comment.DisagreeNum = 0 + comment.CreatedAt = time.Now() + if err := db.Create(&comment).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + answer.Comments = append(answer.Comments, comment) + + if err := db.Save(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + //将评论存入数据库 + if err := db.Save(&comment).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"message": "评论成功"}) + +} + +// 软删除对答案的评论 +func (comment *Comment) delete_comment_to_answer(answer *Answer) { + db.Delete(comment) + len := len(answer.Comments) + answer.Comments = append(answer.Comments[:len], answer.Comments[len:]...) +} + +func DeleteCommentToAnswer(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + var comment Comment + comment.Init(c) + + if err := db.Where("id =?", comment.ID).First(&comment).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + if comment.UserID != userID.(uint) && !CheckManager(userID.(uint)) { + c.JSON(http.StatusUnauthorized, gin.H{"error": "您没有权限删除该问题"}) + return + } + + var answer Answer + if err := db.Where("id =?", comment.AnswerID).First(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + comment.delete_comment_to_answer(&answer) + + c.JSON(http.StatusOK, gin.H{"message": "评论删除成功,可自行选择恢复"}) + +} + +// 恢复对答案的评论 +func RestoreCommentToAnswer(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + + var comment Comment + comment.Init(c) + db.Unscoped().Model(&comment).Update("deleted_at", nil) + + var answer Answer + if err := db.Where("id =?", comment.AnswerID).First(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + answer.Comments = append(answer.Comments, comment) + + c.JSON(http.StatusOK, gin.H{"message": "评论恢复成功"}) +} + +//永久删除对答案的评论 + +func (comment *Comment) delete_comment_forever(answer *Answer) { + db.Unscoped().Delete(comment) + len := len(answer.Comments) + answer.Comments = append(answer.Comments[:len], answer.Comments[len:]...) +} +func DeleteCommentForever(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + + var comment Comment + comment.Init(c) + + if err := db.Unscoped().Where("id =?", comment.ID).First(&comment).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + if comment.UserID != userID.(uint) && !CheckManager(userID.(uint)) { + c.JSON(http.StatusUnauthorized, gin.H{"error": "您没有权限删除该问题"}) + return + } + + var answer Answer + if err := db.Where("id =?", comment.AnswerID).First(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + comment.delete_comment_forever(&answer) + + c.JSON(http.StatusOK, gin.H{"message": "评论删除成功"}) + +} + +// 关键词搜索 +func SearchQuestionsByKeyword(c *gin.Context) { + + var keyword KeyWord + if err := c.ShouldBindJSON(&keyword); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数有误"}) + return + } + if keyword.Keyword == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "请输入搜索关键词"}) + return + } + + var questions []Question + if err := db.Where("UPPER(title) LIKE UPPER(?) OR UPPER(content) LIKE UPPER(?)", "%"+keyword.Keyword+"%", "%"+keyword.Keyword+"%").Find(&questions).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"questions": questions}) +} + +// 对其他评论的评论进行回复 +func CreateReplyToComment(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + answer_id := c.Query("answer_id") + comment_id := c.Query("comment_id") + if answer_id == "" || comment_id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数有误"}) + return + } + var reply Comment + var comment Comment + var answer Answer + if c.ShouldBindJSON(&reply) != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数有误"}) + return + } + if reply.Content == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "评论内容不能为空"}) + return + } + + if err := db.Where("id =?", comment_id).First(&comment).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + if err := db.Where("id =?", answer_id).First(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + reply.UserID = userID.(uint) + reply.AnswerID = answer.ID + + if err := db.Save(&reply).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + if err := db.Save(&comment).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + if err := db.Save(&answer).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + var replyComment ReplyComment + replyComment.ReplyCommentID = reply.ID + replyComment.CommentID = comment.ID + replyComment.ReplyUserID = userID.(uint) + replyComment.CommentUserID = comment.UserID + if err := db.Save(&replyComment).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"message": "评论成功"}) + +} + +//查看对自己的回复 + +func GetReplysToSelf(c *gin.Context) { + userID := CheckLogin(c) + if userID == nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"}) + return + } + + var replys []Comment + var replyComment []ReplyComment + //查找CommentUserID = userID的所有回复 + if err := db.Where("comment_user_id =?", userID.(uint)).Order("created_at desc").Find(&replyComment).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + for _, v := range replyComment { + var newReplys []Comment + if err := db.Where("id =?", v.ReplyCommentID).Find(&newReplys).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + replys = append(replys, newReplys...) + } + + c.JSON(http.StatusOK, gin.H{"replys": replys}) +}