switched to gin-gonic
This commit is contained in:
38
go.mod
38
go.mod
@@ -3,17 +3,41 @@ module GoMembership
|
||||
go 1.22.2
|
||||
|
||||
require (
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/mattn/go-sqlite3 v1.14.22
|
||||
golang.org/x/crypto v0.24.0
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
gorm.io/driver/sqlite v1.5.6
|
||||
gorm.io/gorm v1.25.10
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.11.9 // indirect
|
||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.4 // indirect
|
||||
github.com/gin-contrib/sse v0.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.22.0 // indirect
|
||||
github.com/goccy/go-json v0.10.3 // 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/mattn/go-sqlite3 v1.14.22 // 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.2 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/crypto v0.25.0 // indirect
|
||||
golang.org/x/net v0.27.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
|
||||
gorm.io/driver/sqlite v1.5.6 // indirect
|
||||
gorm.io/gorm v1.25.10 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
95
go.sum
95
go.sum
@@ -1,20 +1,103 @@
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/bytedance/sonic v1.11.9 h1:LFHENlIY/SLzDWverzdOvgMztTxcfcF+cqNsz9pK5zg=
|
||||
github.com/bytedance/sonic v1.11.9/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
||||
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/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 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.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I=
|
||||
github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s=
|
||||
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/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.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
|
||||
github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
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/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
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.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
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/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
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 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
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/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||
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.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
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/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||
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/sqlite v1.5.6 h1:fO/X46qn5NUEEOZtnjJRWRzZMe8nqJiQ9E+0hi+hKQE=
|
||||
gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
|
||||
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
|
||||
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"GoMembership/internal/config"
|
||||
"GoMembership/internal/models"
|
||||
"GoMembership/internal/services"
|
||||
|
||||
// "github.com/gorilla/mux"
|
||||
"net/http"
|
||||
// "strconv"
|
||||
"GoMembership/internal/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"GoMembership/pkg/logger"
|
||||
)
|
||||
|
||||
@@ -26,24 +24,23 @@ func NewMembershipController(service services.MembershipService) *MembershipCont
|
||||
return &MembershipController{service}
|
||||
}
|
||||
|
||||
func (uc *MembershipController) RegisterSubscription(w http.ResponseWriter, r *http.Request) {
|
||||
rh := utils.NewResponseHandler(w)
|
||||
func (uc *MembershipController) RegisterSubscription(c *gin.Context) {
|
||||
var regData MembershipData
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(®Data); err != nil {
|
||||
logger.Error.Printf("Couldn't decode SubscriptionModel: %v", err)
|
||||
rh.RespondWithError(http.StatusBadRequest, "Couldn't decode Membershipmodel")
|
||||
return
|
||||
if err := c.ShouldBindJSON(®Data); err != nil {
|
||||
logger.Error.Printf("Couln't decode subscription data: %v", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Couldn't decode subscription data"})
|
||||
}
|
||||
|
||||
logger.Info.Printf("Using API key: %v", config.LoadConfig().Auth.APIKEY)
|
||||
|
||||
if regData.APIKey == "" {
|
||||
logger.Error.Println("API Key is missing")
|
||||
rh.RespondWithError(http.StatusBadRequest, "API Key is required")
|
||||
c.JSON(http.StatusBadRequest, "API Key is missing")
|
||||
return
|
||||
}
|
||||
if regData.APIKey != config.LoadConfig().Auth.APIKEY {
|
||||
logger.Error.Printf("API Key not valid: %v", regData.APIKey)
|
||||
rh.RespondWithError(http.StatusExpectationFailed, "API Key not valid")
|
||||
c.JSON(http.StatusExpectationFailed, "API Key is missing")
|
||||
return
|
||||
}
|
||||
logger.Info.Printf("registering subscription: %+v", regData)
|
||||
@@ -52,7 +49,7 @@ func (uc *MembershipController) RegisterSubscription(w http.ResponseWriter, r *h
|
||||
id, err := uc.service.RegisterSubscription(®Data.Model)
|
||||
if err != nil {
|
||||
logger.Error.Printf("Couldn't register Membershipmodel: %v", err)
|
||||
rh.RespondWithError(http.StatusInternalServerError, "Couldn't register Membershipmodel")
|
||||
c.JSON(http.StatusInternalServerError, "Couldn't register Membershipmodel")
|
||||
return
|
||||
}
|
||||
regData.Model.ID = id
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"GoMembership/internal/models"
|
||||
"GoMembership/internal/services"
|
||||
|
||||
// "github.com/gorilla/mux"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
// "strconv"
|
||||
"GoMembership/internal/utils"
|
||||
|
||||
"GoMembership/pkg/logger"
|
||||
)
|
||||
|
||||
@@ -31,15 +28,13 @@ func NewUserController(service services.UserService, emailService *services.Emai
|
||||
return &UserController{service, *emailService, consentService, bankAccountService, membershipService}
|
||||
}
|
||||
|
||||
func (uc *UserController) RegisterUser(w http.ResponseWriter, r *http.Request) {
|
||||
rh := utils.NewResponseHandler(w)
|
||||
func (uc *UserController) RegisterUser(c *gin.Context) {
|
||||
|
||||
var regData RegistrationData
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(®Data); err != nil {
|
||||
// http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
if err := c.ShouldBindJSON(®Data); err != nil {
|
||||
logger.Error.Printf("Couldn't decode Userdata: %v", err)
|
||||
rh.RespondWithError(http.StatusBadRequest, "Couldn't decode userdata")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Couldn't decode userdata"})
|
||||
return
|
||||
}
|
||||
logger.Info.Printf("registering user: %v", regData.User)
|
||||
@@ -47,9 +42,8 @@ func (uc *UserController) RegisterUser(w http.ResponseWriter, r *http.Request) {
|
||||
// Register User
|
||||
id, token, err := uc.service.RegisterUser(®Data.User)
|
||||
if err != nil {
|
||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
logger.Error.Printf("Couldn't register User: %v", err)
|
||||
rh.RespondWithError(http.StatusInternalServerError, "Couldn't register User")
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Couldn't register User"})
|
||||
return
|
||||
}
|
||||
regData.User.ID = id
|
||||
@@ -58,7 +52,7 @@ func (uc *UserController) RegisterUser(w http.ResponseWriter, r *http.Request) {
|
||||
_, err = uc.bankAccountService.RegisterBankAccount(®Data.BankAccount)
|
||||
if err != nil {
|
||||
logger.Error.Printf("Couldn't register bank account: %v", err)
|
||||
rh.RespondWithError(http.StatusInternalServerError, "Couldn't register User-BankAccount")
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Couldn't register User-BankAccount"})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -81,7 +75,7 @@ func (uc *UserController) RegisterUser(w http.ResponseWriter, r *http.Request) {
|
||||
_, err = uc.consentService.RegisterConsent(&consent)
|
||||
if err != nil {
|
||||
logger.Error.Printf("Couldn't register consent: %v", err)
|
||||
rh.RespondWithError(http.StatusInternalServerError, "Couldn't register User-consent")
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Couldn't register User-consent"})
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -90,48 +84,53 @@ func (uc *UserController) RegisterUser(w http.ResponseWriter, r *http.Request) {
|
||||
_, err = uc.membershipService.RegisterMembership(®Data.Membership)
|
||||
if err != nil {
|
||||
logger.Error.Printf("Couldn't register membership: %v", err)
|
||||
rh.RespondWithError(http.StatusInternalServerError, "Couldn't register User-membership")
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Couldn't register User-membership"})
|
||||
return
|
||||
}
|
||||
|
||||
// Send notifications
|
||||
if err := uc.emailService.SendVerificationEmail(®Data.User, &token); err != nil {
|
||||
logger.Error.Printf("Failed to send email verification email to user: %v", err)
|
||||
// rh.RespondWithError(http.StatusServiceUnavailable, "User creation succeeded, but failed to send welcome email to user")
|
||||
// Proceed without returning error since user registration is successful
|
||||
}
|
||||
|
||||
// Notify admin of new user registration
|
||||
if err := uc.emailService.NotifyAdminOfNewUser(®Data.User); err != nil {
|
||||
logger.Error.Printf("Failed to notify admin of new user registration: %v", err)
|
||||
// rh.RespondWithError(http.StatusServiceUnavailable, "User creation succeeded, but failed to notify admin of new user registration")
|
||||
// Proceed without returning error since user registration is successful
|
||||
}
|
||||
rh.RespondWithJSON(http.StatusCreated, map[string]interface{}{
|
||||
|
||||
c.JSON(http.StatusCreated, gin.H{
|
||||
"status": "success",
|
||||
"id": regData.User.ID,
|
||||
})
|
||||
}
|
||||
|
||||
func (uc *UserController) VerifyMailHandler(w http.ResponseWriter, r *http.Request) {
|
||||
rh := utils.NewResponseHandler(w)
|
||||
|
||||
token := r.URL.Query().Get("token")
|
||||
func (uc *UserController) VerifyMailHandler(c *gin.Context) {
|
||||
token := c.Query("token")
|
||||
if token == "" {
|
||||
logger.Error.Println("Missing token to verify mail")
|
||||
rh.RespondWithError(http.StatusNoContent, "Missing token")
|
||||
c.JSON(http.StatusNoContent, gin.H{"error": "Missing token"})
|
||||
return
|
||||
}
|
||||
|
||||
user, err := uc.service.VerifyUser(&token)
|
||||
if err != nil {
|
||||
logger.Error.Printf("Cannot verify user: %v", err)
|
||||
rh.RespondWithError(http.StatusUnauthorized, "Cannot verify user")
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "Cannot verify user"})
|
||||
return
|
||||
}
|
||||
|
||||
membership, err := uc.membershipService.FindMembershipByUserID(user.ID)
|
||||
if err != nil {
|
||||
logger.Error.Printf("Cannot get membership of user %v: %v", user.ID, err)
|
||||
rh.RespondWithError(http.StatusInternalServerError, "Cannot get Membership of user")
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Cannot get Membership of user"})
|
||||
return
|
||||
}
|
||||
|
||||
uc.emailService.SendWelcomeEmail(user, membership)
|
||||
c.Status(http.StatusOK)
|
||||
|
||||
}
|
||||
|
||||
/* func (uc *UserController) LoginUser(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -1,17 +1,33 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"GoMembership/pkg/logger"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"GoMembership/pkg/logger"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// LoggerMiddleware logs each incoming HTTP request
|
||||
func LoggerMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
logger.Info.Printf("%s %s %s", r.Method, r.RequestURI, time.Since(start))
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
// LoggerMiddleware logs the incoming requests.
|
||||
func LoggerMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
startTime := time.Now()
|
||||
|
||||
// Process the request
|
||||
c.Next()
|
||||
|
||||
// Calculate the latency
|
||||
latency := time.Since(startTime)
|
||||
|
||||
// Get the status code
|
||||
statusCode := c.Writer.Status()
|
||||
|
||||
// Log the details
|
||||
logger.Info.Printf("| %3d | %13v | %15s | %-7s %#v\n",
|
||||
statusCode,
|
||||
latency,
|
||||
c.ClientIP(),
|
||||
c.Request.Method,
|
||||
c.Request.URL.Path,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,27 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"GoMembership/internal/constants"
|
||||
"time"
|
||||
|
||||
"GoMembership/internal/constants"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"gorm.io/gorm/clause"
|
||||
|
||||
"GoMembership/internal/models"
|
||||
"GoMembership/pkg/errors"
|
||||
"gorm.io/gorm/clause"
|
||||
"GoMembership/pkg/logger"
|
||||
)
|
||||
|
||||
type UserRepository interface {
|
||||
CreateUser(user *models.User) (int64, error)
|
||||
UpdateUser(userID int64, user *models.User) error
|
||||
FindUserByID(id int64) (*models.User, error)
|
||||
FindUserByEmail(email string) (*models.User, error)
|
||||
SetVerificationToken(user *models.User, token *string) (int64, error)
|
||||
IsVerified(userID *int64) (bool, error)
|
||||
VerifyUserOfToken(token *string) (int64, error)
|
||||
VerifyUserOfToken(token *string) (*models.User, error)
|
||||
}
|
||||
|
||||
type userRepository struct {
|
||||
@@ -36,11 +40,12 @@ func (repo *userRepository) CreateUser(user *models.User) (int64, error) {
|
||||
return user.ID, nil
|
||||
}
|
||||
|
||||
func (repo *userRepository) UpdateUser(userID int64, updates map[string]interface{}) error {
|
||||
if len(updates) == 0 {
|
||||
func (repo *userRepository) UpdateUser(userID int64, user *models.User) error {
|
||||
logger.Info.Printf("Updating User: %#v\n", user)
|
||||
if user == nil {
|
||||
return errors.ErrNoData
|
||||
}
|
||||
result := repo.db.Session(&gorm.Session{FullSaveAssociations: true}).Model(&models.User{}).Where("id = ?", userID).Updates(&updates)
|
||||
result := repo.db.Session(&gorm.Session{FullSaveAssociations: true}).Updates(&user)
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
@@ -54,7 +59,7 @@ func (repo *userRepository) UpdateUser(userID int64, updates map[string]interfac
|
||||
|
||||
func (repo *userRepository) FindUserByID(id int64) (*models.User, error) {
|
||||
var user models.User
|
||||
result := repo.db.First(&user, id)
|
||||
result := repo.db.Preload("Consents").Preload("BankAccount").Preload("Verification").Preload("Membership").First(&user, id)
|
||||
if result.Error != nil {
|
||||
if result.Error == gorm.ErrRecordNotFound {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
@@ -88,38 +93,40 @@ func (repo *userRepository) IsVerified(userID *int64) (bool, error) {
|
||||
return user.Status != constants.UnverifiedStatus, nil
|
||||
}
|
||||
|
||||
func (repo *userRepository) VerifyUserOfToken(token *string) (int64, error) {
|
||||
func (repo *userRepository) VerifyUserOfToken(token *string) (*models.User, error) {
|
||||
var emailVerification models.Verification
|
||||
result := repo.db.Where("verification_token = ?", token).First(&emailVerification)
|
||||
if result.Error != nil {
|
||||
if result.Error == gorm.ErrRecordNotFound {
|
||||
return 0, gorm.ErrRecordNotFound
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return 0, result.Error
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
// Check if the user is already verified
|
||||
verified, err := repo.IsVerified(&emailVerification.UserID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return nil, err
|
||||
}
|
||||
user, err := repo.FindUserByID(emailVerification.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if verified {
|
||||
return emailVerification.UserID, gorm.ErrRecordNotFound
|
||||
return user, errors.ErrAlreadyVerified
|
||||
}
|
||||
|
||||
// Update user status to active
|
||||
t := time.Now()
|
||||
emailVerification.EmailVerifiedAt = &t
|
||||
update := map[string]interface{}{
|
||||
"status": constants.VerifiedStatus,
|
||||
"verifications": emailVerification,
|
||||
}
|
||||
err = repo.UpdateUser(emailVerification.UserID, update)
|
||||
user.Status = constants.VerifiedStatus
|
||||
user.Verification = emailVerification
|
||||
|
||||
err = repo.UpdateUser(emailVerification.UserID, user)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return emailVerification.UserID, nil
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (repo *userRepository) SetVerificationToken(user *models.User, token *string) (int64, error) {
|
||||
|
||||
@@ -2,18 +2,14 @@ package routes
|
||||
|
||||
import (
|
||||
"GoMembership/internal/controllers"
|
||||
// "GoMembership/internal/middlewares"
|
||||
"GoMembership/pkg/logger"
|
||||
// "net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterRoutes(router *mux.Router, userController *controllers.UserController, membershipController *controllers.MembershipController) {
|
||||
logger.Info.Println("Registering backend/api/register route")
|
||||
router.HandleFunc("/backend/api/verify", userController.VerifyMailHandler).Methods("GET")
|
||||
router.HandleFunc("/backend/api/register", userController.RegisterUser).Methods("POST")
|
||||
router.HandleFunc("/backend/api/register/subscription", membershipController.RegisterSubscription).Methods("POST")
|
||||
func RegisterRoutes(router *gin.Engine, userController *controllers.UserController, membershipController *controllers.MembershipController) {
|
||||
router.GET("/backend/verify", userController.VerifyMailHandler)
|
||||
router.POST("/backend/api/register", userController.RegisterUser)
|
||||
router.POST("/backend/api/register/subscription", membershipController.RegisterSubscription)
|
||||
// router.HandleFunc("/login", userController.LoginUser).Methods("POST")
|
||||
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@ import (
|
||||
"GoMembership/internal/config"
|
||||
"GoMembership/internal/controllers"
|
||||
"GoMembership/internal/database"
|
||||
"GoMembership/internal/middlewares"
|
||||
// "GoMembership/internal/middlewares"
|
||||
"GoMembership/internal/repositories"
|
||||
"GoMembership/internal/routes"
|
||||
"GoMembership/internal/services"
|
||||
"GoMembership/pkg/logger"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func Run() {
|
||||
@@ -35,12 +35,11 @@ func Run() {
|
||||
userService := services.NewUserService(userRepo)
|
||||
userController := controllers.NewUserController(userService, emailService, consentService, bankAccountService, membershipService)
|
||||
membershipController := controllers.NewMembershipController(membershipService)
|
||||
router := mux.NewRouter()
|
||||
// router.Handle("/csrf-token", middlewares.GenerateCSRFTokenHandler()).Methods("GET")
|
||||
|
||||
// Apply CSRF middleware
|
||||
// router.Use(middlewares.CSRFMiddleware)
|
||||
router.Use(middlewares.LoggerMiddleware)
|
||||
router := gin.Default()
|
||||
// gin.SetMode(gin.ReleaseMode)
|
||||
router.Use(gin.Logger())
|
||||
// router.Use(middlewares.LoggerMiddleware())
|
||||
|
||||
routes.RegisterRoutes(router, userController, membershipController)
|
||||
// create subrouter for teh authenticated area /account
|
||||
|
||||
@@ -39,6 +39,7 @@ func (service *userService) RegisterUser(user *models.User) (int64, string, erro
|
||||
return -1, err
|
||||
}
|
||||
user.Password = string(hashedPassword) */
|
||||
// TODO: Validate Data
|
||||
user.Status = constants.UnverifiedStatus
|
||||
user.CreatedAt = time.Now()
|
||||
user.UpdatedAt = time.Now()
|
||||
@@ -53,7 +54,7 @@ func (service *userService) RegisterUser(user *models.User) (int64, string, erro
|
||||
return -1, "", err
|
||||
}
|
||||
|
||||
logger.Info.Printf("user: %+v", user)
|
||||
logger.Info.Printf("TOKEN: %v", token)
|
||||
_, err = service.repo.SetVerificationToken(user, &token)
|
||||
if err != nil {
|
||||
return -1, "", err
|
||||
@@ -62,11 +63,7 @@ func (service *userService) RegisterUser(user *models.User) (int64, string, erro
|
||||
}
|
||||
|
||||
func (service *userService) VerifyUser(token *string) (*models.User, error) {
|
||||
userID, err := service.repo.VerifyUserOfToken(token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user, err := service.repo.FindUserByID(userID)
|
||||
user, err := service.repo.VerifyUserOfToken(token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,67 +1,110 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Willkommen beim Dörpsmobil Hasloh e.V.</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
<!doctype html>
|
||||
<html>
|
||||
<body>
|
||||
<div
|
||||
style="
|
||||
background-color: #f2f5f7;
|
||||
color: #242424;
|
||||
font-family: "Helvetica Neue", "Arial Nova",
|
||||
"Nimbus Sans", Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.15008px;
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
}
|
||||
h1 {
|
||||
color: #007b5e;
|
||||
}
|
||||
p {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.contact-info {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.contact-info strong {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
a {
|
||||
color: #007b5e;
|
||||
padding: 32px 0;
|
||||
min-height: 100%;
|
||||
width: 100%;
|
||||
"
|
||||
>
|
||||
<table
|
||||
align="center"
|
||||
width="100%"
|
||||
style="margin: 0 auto; max-width: 600px; background-color: #ffffff"
|
||||
role="presentation"
|
||||
cellspacing="0"
|
||||
cellpadding="0"
|
||||
border="0"
|
||||
>
|
||||
<tbody>
|
||||
<tr style="width: 100%">
|
||||
<td>
|
||||
<div style="padding: 0px 24px 0px 24px">
|
||||
<a
|
||||
href="https://carsharing-hasloh.de"
|
||||
style="text-decoration: none"
|
||||
target="_blank"
|
||||
><img
|
||||
alt="Carsharing-Hasloh"
|
||||
src="https://carsharing-hasloh.de/images/CarsharingSH-Hasloh-LOGO.jpeg"
|
||||
style="
|
||||
outline: none;
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>{{.Firstname}} {{.LastName}} hat sich registriert</h1>
|
||||
<p>Ein neues Vereinsmitglied hat sich registriert</p>
|
||||
<p>{{.Firstname}} {{.LastName}} hat sich registriert. Hier sind die Daten:</p>
|
||||
<br>
|
||||
<div class="contact-info">
|
||||
<strong>Registrierungsdaten:</strong>
|
||||
Name: {{.Firstname}} {{.LastName}} <br>
|
||||
Email: {{.Email}}<br>
|
||||
IBAN: {{.IBAN}}<br>
|
||||
BIC: {{.BIC}}<br>
|
||||
Mandatsreferenz: {{.MandateReference}}<br>
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
"
|
||||
/></a>
|
||||
</div>
|
||||
<p>Mit freundlichen Grüßen,<br>
|
||||
der Server
|
||||
<div style="font-weight: normal; padding: 0px 24px 16px 24px">
|
||||
Moin Du Vorstand 👋,
|
||||
</div>
|
||||
<div style="font-weight: normal; padding: 0px 24px 16px 24px">
|
||||
<p>
|
||||
Ein neues Mitglied!!!<br />{{.FirstName}} {{.LastName}} hat
|
||||
sich regitriert.
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
<div
|
||||
style="
|
||||
font-size: 22px;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
padding: 0px 24px 0px 24px;
|
||||
"
|
||||
>
|
||||
Hier sind die Daten:
|
||||
</div>
|
||||
<div style="font-weight: normal; padding: 16px 24px 0px 24px">
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Das gebuchtes Modell</strong>:
|
||||
<ul>
|
||||
<li><strong>Name</strong>: {{.Modellname}}</li>
|
||||
<li><strong>Preis/Monat</strong>: {{.PreisMonat}}</li>
|
||||
<li><strong>Preis/h</strong>: {{.PreisStunde}}</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>Name:</strong> {{.FirstName}} {{.LastName}}</li>
|
||||
<li>
|
||||
<strong>Adresse:</strong> {{.Address}},{{.ZipCode}}
|
||||
{{.City}}
|
||||
</li>
|
||||
<li><strong>Geburtsdatum:</strong> {{.DateOfBirth}}</li>
|
||||
<li><strong>Email:</strong> {{.Email}}</li>
|
||||
<li><strong>Telefon:</strong> {{.Phone}}</li>
|
||||
<li><strong>IBAN:</strong> {{.IBAN}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div style="padding: 16px 0px 16px 0px">
|
||||
<hr
|
||||
style="
|
||||
width: 100%;
|
||||
border: none;
|
||||
border-top: 1px solid #cccccc;
|
||||
margin: 0;
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div style="font-weight: normal; padding: 16px 24px 16px 24px">
|
||||
<p>Mit freundlichen Grüßen,</p>
|
||||
<p>Dein untertänigster Wolkenrechner</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user