added questions, replies and likes functionality"
parent
437a4f6e63
commit
6a9cde458a
36
go.mod
36
go.mod
|
@ -4,38 +4,40 @@ go 1.21.0
|
|||
|
||||
require (
|
||||
git.ex.umbach.dev/Alex/roese-utils v1.0.21
|
||||
git.ex.umbach.dev/LMS/libcore v1.0.6
|
||||
git.ex.umbach.dev/LMS/libcore v1.0.8
|
||||
github.com/gofiber/fiber/v2 v2.52.5
|
||||
github.com/gofiber/websocket/v2 v2.2.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/rs/zerolog v1.31.0
|
||||
golang.org/x/crypto v0.14.0
|
||||
github.com/rs/zerolog v1.33.0
|
||||
golang.org/x/crypto v0.27.0
|
||||
gorm.io/driver/mysql v1.5.7
|
||||
gorm.io/gorm v1.25.11
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/fasthttp/websocket v1.5.3 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/fasthttp/websocket v1.5.10 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.5 // 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.15.5 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.22.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/klauspost/compress v1.17.0 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect
|
||||
github.com/stretchr/testify v1.9.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.51.0 // indirect
|
||||
github.com/valyala/fasthttp v1.55.0 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/text v0.17.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
|
||||
)
|
||||
|
|
47
go.sum
47
go.sum
|
@ -4,20 +4,17 @@ git.ex.umbach.dev/Alex/roese-utils v1.0.21 h1:ae1AHQh8UHJVLbpk5Gf4S5IP0EEWGD1JFI
|
|||
git.ex.umbach.dev/Alex/roese-utils v1.0.21/go.mod h1:hFcnKQl6nuGFEMCxK/eVQBUD6ixBFlAaiy4E2aQqUL8=
|
||||
git.ex.umbach.dev/LMS/libcore v1.0.6 h1:Af+2jD4aC3+4qMgSmTn4nvRosAS5ETTX9JR3gznlGPI=
|
||||
git.ex.umbach.dev/LMS/libcore v1.0.6/go.mod h1:BvbMJWYQ83dblDAB4ooLfwuorjdy6G3txdOrjRfIKPA=
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
git.ex.umbach.dev/LMS/libcore v1.0.7 h1:bKt02PY0FffHU79EnW5k6HvySLt4KgyKmb7duulweTM=
|
||||
git.ex.umbach.dev/LMS/libcore v1.0.7/go.mod h1:BvbMJWYQ83dblDAB4ooLfwuorjdy6G3txdOrjRfIKPA=
|
||||
git.ex.umbach.dev/LMS/libcore v1.0.8 h1:6OLKoWEiSy+rm/UdKFASGWzR7hQocBKPA5KR8zsdzLY=
|
||||
git.ex.umbach.dev/LMS/libcore v1.0.8/go.mod h1:BvbMJWYQ83dblDAB4ooLfwuorjdy6G3txdOrjRfIKPA=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
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/fasthttp/websocket v1.5.3 h1:TPpQuLwJYfd4LJPXvHDYPMFWbLjsT91n3GpWtCQtdek=
|
||||
github.com/fasthttp/websocket v1.5.3/go.mod h1:46gg/UBmTU1kUaTcwQXpUxtRwG2PvIZYeA8oL6vF3Fs=
|
||||
github.com/fasthttp/websocket v1.5.10 h1:bc7NIGyrg1L6sd5pRzCIbXpro54SZLEluZCu0rOpcN4=
|
||||
github.com/fasthttp/websocket v1.5.10/go.mod h1:BwHeuXGWzCW1/BIKUKD3+qfCl+cTdsHu/f243NcAI/Q=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
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/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
|
@ -26,11 +23,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
|||
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.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24=
|
||||
github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
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/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
||||
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=
|
||||
|
@ -47,12 +41,8 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
|||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
|
@ -61,63 +51,38 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
|
|||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
|
||||
github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
|
||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
|
||||
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc=
|
||||
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg=
|
||||
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.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.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
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/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
|
||||
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
|
||||
github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8=
|
||||
github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM=
|
||||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
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.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.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.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
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=
|
||||
|
|
|
@ -44,6 +44,4 @@ func InitDatabase() {
|
|||
db.AutoMigrate(&models.LessonContent{})
|
||||
db.AutoMigrate(&models.Question{})
|
||||
db.AutoMigrate(&models.QuestionLike{})
|
||||
db.AutoMigrate(&models.QuestionReply{})
|
||||
db.AutoMigrate(&models.QuestionReplyLike{})
|
||||
}
|
||||
|
|
|
@ -1 +1,18 @@
|
|||
package structs
|
||||
|
||||
import "git.ex.umbach.dev/LMS/libcore/models"
|
||||
|
||||
type QuestionsResponse struct {
|
||||
Questions []models.Question
|
||||
LikedQuestions []string
|
||||
}
|
||||
|
||||
// swagger:model CreateQuestionRequest
|
||||
type CreateQuestionRequest struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
type LessonIdQuestionIdParam struct {
|
||||
LessonId string
|
||||
QuestionId string
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
package structs
|
||||
|
||||
// swagger:model GetUserResponse
|
||||
type GetUserResponse struct {
|
||||
AvatarUrl string
|
||||
Id string
|
||||
FirstName string
|
||||
LastName string
|
||||
ProfilePictureUrl string
|
||||
}
|
||||
|
||||
// swagger:model UserLoginRequest
|
||||
|
@ -53,3 +57,7 @@ type GetUserProfileResponse struct {
|
|||
Email string
|
||||
RoleId string
|
||||
}
|
||||
|
||||
type UserIdParam struct {
|
||||
UserId string
|
||||
}
|
||||
|
|
|
@ -97,6 +97,11 @@ const (
|
|||
SendCmdLessonContentUpdatedPosition = 15
|
||||
SendCmdLessonContentFileUpdated = 16
|
||||
SendCmdUserProfilePictureUpdated = 17
|
||||
SendCmdLessonQuestionCreated = 18
|
||||
SendCmdLessonQuestionLiked = 19
|
||||
SendCmdLessonQuestionCountUpLikes = 20
|
||||
SendCmdLessonQuestionDisliked = 21
|
||||
SendCmdLessonQuestionCountDownLikes = 22
|
||||
)
|
||||
|
||||
// commands received from websocket clients
|
||||
|
|
|
@ -27,13 +27,20 @@ func GetApp(c *fiber.Ctx) error {
|
|||
|
||||
var user models.User
|
||||
|
||||
database.DB.Model(&models.User{
|
||||
Id: c.Locals("userId").(string),
|
||||
}).Select("profile_picture_url").First(&user)
|
||||
if err := database.DB.Model(&models.User{}).
|
||||
Where("id = ?", c.Locals("userId").(string)).
|
||||
Select("profile_picture_url").First(&user).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
var organization models.Organization
|
||||
|
||||
database.DB.Model(&models.Organization{}).Select("company_name", "primary_color", "logo_url", "banner_url").Where("id = ?", c.Locals("organizationId").(string)).First(&organization)
|
||||
if err := database.DB.Model(&models.Organization{}).
|
||||
Select("company_name", "primary_color", "logo_url", "banner_url").
|
||||
Where("id = ?", c.Locals("organizationId").(string)).
|
||||
First(&organization).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return c.JSON(structs.GetAppResponse{
|
||||
User: structs.AppUser{
|
||||
|
|
|
@ -35,7 +35,9 @@ func GetLessons(c *fiber.Ctx) error {
|
|||
|
||||
var lessons []structs.LessonResponse
|
||||
|
||||
if err := database.DB.Model(&models.Lesson{}).Where("organization_id = ?", c.Locals("organizationId")).Find(&lessons).Error; err != nil {
|
||||
if err := database.DB.Model(&models.Lesson{}).
|
||||
Where("organization_id = ?", c.Locals("organizationId")).
|
||||
Find(&lessons).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
@ -116,9 +118,23 @@ func GetLessonContents(c *fiber.Ctx) error {
|
|||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
// check if lesson belongs to organization
|
||||
|
||||
var lesson models.Lesson
|
||||
|
||||
if err := database.DB.Model(&models.Lesson{}).
|
||||
Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)).
|
||||
First(&lesson).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
||||
// get lesson contents
|
||||
|
||||
var lessonContents []structs.GetLessonContentsResponse
|
||||
|
||||
if err := database.DB.Model(&models.LessonContent{}).Where("lesson_id = ?", params.LessonId).Find(&lessonContents).Error; err != nil {
|
||||
if err := database.DB.Model(&models.LessonContent{}).
|
||||
Where("lesson_id = ?", params.LessonId).
|
||||
Find(&lessonContents).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
@ -160,7 +176,9 @@ func GetLessonSettings(c *fiber.Ctx) error {
|
|||
|
||||
var lessonSettings structs.LessonSettings
|
||||
|
||||
if err := database.DB.Model(&models.Lesson{}).Where("id = ?", params.LessonId).First(&lessonSettings).Error; err != nil {
|
||||
if err := database.DB.Model(&models.Lesson{}).
|
||||
Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)).
|
||||
First(&lessonSettings).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
@ -204,7 +222,9 @@ func UpdateLessonPreviewTitle(c *fiber.Ctx) error {
|
|||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
if err := database.DB.Model(&models.Lesson{}).Where("id = ?", params.LessonId).Update("title", body.Title).Error; err != nil {
|
||||
if err := database.DB.Model(&models.Lesson{}).
|
||||
Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)).
|
||||
Update("title", body.Title).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
@ -278,7 +298,9 @@ func UpdateLessonPreviewThumbnail(c *fiber.Ctx) error {
|
|||
|
||||
lesson := models.Lesson{}
|
||||
|
||||
if err := database.DB.Model(&models.Lesson{}).Where("id = ?", params.LessonId).First(&lesson).Error; err != nil {
|
||||
if err := database.DB.Model(&models.Lesson{}).
|
||||
Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)).
|
||||
First(&lesson).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
@ -296,7 +318,9 @@ func UpdateLessonPreviewThumbnail(c *fiber.Ctx) error {
|
|||
|
||||
thumbnailUrl := databasePath + fileName
|
||||
|
||||
if err := database.DB.Model(&models.Lesson{}).Where("id = ?", params.LessonId).Update("thumbnail_url", thumbnailUrl).Error; err != nil {
|
||||
if err := database.DB.Model(&models.Lesson{}).
|
||||
Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)).
|
||||
Update("thumbnail_url", thumbnailUrl).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
@ -362,8 +386,7 @@ func UpdateLessonState(c *fiber.Ctx) error {
|
|||
}
|
||||
|
||||
if err := database.DB.Model(&models.Lesson{}).
|
||||
Where("id = ?", params.LessonId).
|
||||
Where("organization_id = ?", c.Locals("organizationId").(string)).
|
||||
Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)).
|
||||
Update("state", body.State).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
@ -428,11 +451,25 @@ func AddLessonContent(c *fiber.Ctx) error {
|
|||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
// check if lesson belongs to organization
|
||||
|
||||
var lesson models.Lesson
|
||||
|
||||
if err := database.DB.Model(&models.Lesson{}).
|
||||
Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)).
|
||||
First(&lesson).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
||||
// get last position
|
||||
|
||||
var lastContent models.LessonContent
|
||||
|
||||
if err := database.DB.Select("position").Model(&models.LessonContent{}).Where("lesson_id = ?", params.LessonId).Order("position desc").First(&lastContent).Error; err != nil {
|
||||
if err := database.DB.Select("position").
|
||||
Model(&models.LessonContent{}).
|
||||
Where("lesson_id = ?", params.LessonId).
|
||||
Order("position desc").
|
||||
First(&lastContent).Error; err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
@ -532,11 +569,24 @@ func UploadLessonContentFile(c *fiber.Ctx) error {
|
|||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
// check if lesson belongs to organization
|
||||
|
||||
var lesson models.Lesson
|
||||
|
||||
if err := database.DB.Model(&models.Lesson{}).
|
||||
Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)).
|
||||
First(&lesson).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
||||
// get current file
|
||||
|
||||
content := models.LessonContent{}
|
||||
|
||||
if err := database.DB.Select("type", "data").Model(&models.LessonContent{}).Where("id = ?", params.ContentId).First(&content).Error; err != nil {
|
||||
if err := database.DB.Select("type", "data").
|
||||
Model(&models.LessonContent{}).
|
||||
Where("id = ? AND lesson_id = ?", params.ContentId, params.LessonId).
|
||||
First(&content).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
@ -552,7 +602,9 @@ func UploadLessonContentFile(c *fiber.Ctx) error {
|
|||
|
||||
utils.CreateFolderStructureIfNotExists(publicPath)
|
||||
|
||||
if err := database.DB.Model(&models.LessonContent{}).Where("id = ?", params.ContentId).Update("data", databasePath+fileName).Error; err != nil {
|
||||
if err := database.DB.Model(&models.LessonContent{}).
|
||||
Where("id = ? AND lesson_id = ?", params.ContentId, params.LessonId).
|
||||
Update("data", databasePath+fileName).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
@ -624,7 +676,21 @@ func UpdateLessonContent(c *fiber.Ctx) error {
|
|||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
if err := database.DB.Model(&models.LessonContent{}).Where("id = ?", params.ContentId).Update("data", body.Data).Error; err != nil {
|
||||
// check if lesson belongs to organization
|
||||
|
||||
var lesson models.Lesson
|
||||
|
||||
if err := database.DB.Model(&models.Lesson{}).
|
||||
Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)).
|
||||
First(&lesson).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
||||
// update content
|
||||
|
||||
if err := database.DB.Model(&models.LessonContent{}).
|
||||
Where("id = ? AND lesson_id = ?", params.ContentId, params.LessonId).
|
||||
Update("data", body.Data).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
@ -692,6 +758,16 @@ func UpdateLessonContentPosition(c *fiber.Ctx) error {
|
|||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
// check if lesson belongs to organization
|
||||
|
||||
var lesson models.Lesson
|
||||
|
||||
if err := database.DB.Model(&models.Lesson{}).
|
||||
Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)).
|
||||
First(&lesson).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
||||
// update position
|
||||
|
||||
newPosition := body.Position
|
||||
|
@ -704,7 +780,9 @@ func UpdateLessonContentPosition(c *fiber.Ctx) error {
|
|||
|
||||
// Fetch the current position of the content being moved
|
||||
var currentContent models.LessonContent
|
||||
if err := tx.Model(&models.LessonContent{}).Where("id = ?", params.ContentId).First(¤tContent).Error; err != nil {
|
||||
if err := tx.Model(&models.LessonContent{}).
|
||||
Where("id = ? AND lesson_id = ?", params.ContentId, params.LessonId).
|
||||
First(¤tContent).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
@ -720,7 +798,8 @@ func UpdateLessonContentPosition(c *fiber.Ctx) error {
|
|||
|
||||
if oldPosition < newPosition {
|
||||
// Items between oldPosition and newPosition need to be shifted down
|
||||
if err := tx.Model(&models.LessonContent{}).Where("lesson_id = ?", params.LessonId).
|
||||
if err := tx.Model(&models.LessonContent{}).
|
||||
Where("lesson_id = ?", params.LessonId).
|
||||
Where("position > ? AND position <= ?", oldPosition, newPosition).
|
||||
Update("position", gorm.Expr("position - 1")).Error; err != nil {
|
||||
tx.Rollback()
|
||||
|
@ -728,7 +807,8 @@ func UpdateLessonContentPosition(c *fiber.Ctx) error {
|
|||
}
|
||||
} else {
|
||||
// Items between newPosition and oldPosition need to be shifted up
|
||||
if err := tx.Model(&models.LessonContent{}).Where("lesson_id = ?", params.LessonId).
|
||||
if err := tx.Model(&models.LessonContent{}).
|
||||
Where("lesson_id = ?", params.LessonId).
|
||||
Where("position >= ? AND position < ?", newPosition, oldPosition).
|
||||
Update("position", gorm.Expr("position + 1")).Error; err != nil {
|
||||
tx.Rollback()
|
||||
|
@ -737,7 +817,9 @@ func UpdateLessonContentPosition(c *fiber.Ctx) error {
|
|||
}
|
||||
|
||||
// Update the position of the moved content
|
||||
if err := tx.Model(&models.LessonContent{}).Where("id = ?", params.ContentId).Update("position", newPosition).Error; err != nil {
|
||||
if err := tx.Model(&models.LessonContent{}).
|
||||
Where("id = ? AND lesson_id = ?", params.ContentId, params.LessonId).
|
||||
Update("position", newPosition).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
@ -807,9 +889,21 @@ func DeleteLessonContent(c *fiber.Ctx) error {
|
|||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// check if lesson belongs to organization
|
||||
|
||||
var lesson models.Lesson
|
||||
|
||||
if err := database.DB.Model(&models.Lesson{}).
|
||||
Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)).
|
||||
First(&lesson).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
||||
// Fetch the current position of the content being deleted
|
||||
var content models.LessonContent
|
||||
if err := tx.Model(&models.LessonContent{}).Where("id = ?", params.ContentId).First(&content).Error; err != nil {
|
||||
if err := tx.Model(&models.LessonContent{}).
|
||||
Where("id = ? AND lesson_id = ?", params.ContentId, params.LessonId).
|
||||
First(&content).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
@ -821,8 +915,8 @@ func DeleteLessonContent(c *fiber.Ctx) error {
|
|||
}
|
||||
|
||||
// Shift down the positions of all contents with a higher position
|
||||
if err := tx.Model(&models.LessonContent{}).Where("lesson_id = ?", params.LessonId).
|
||||
Where("position > ?", content.Position).
|
||||
if err := tx.Model(&models.LessonContent{}).
|
||||
Where("lesson_id = ? AND position > ?", params.LessonId, content.Position).
|
||||
Update("position", gorm.Expr("position - 1")).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
|
|
|
@ -0,0 +1,452 @@
|
|||
package lessons
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.ex.umbach.dev/LMS/libcore/models"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
"lms.de/backend/modules/database"
|
||||
"lms.de/backend/modules/structs"
|
||||
"lms.de/backend/modules/utils"
|
||||
"lms.de/backend/socketclients"
|
||||
)
|
||||
|
||||
func GetQuestions(c *fiber.Ctx) error {
|
||||
// swagger:operation GET /v1/lessons/{lessonId}/questions questions getQuestions
|
||||
// ---
|
||||
// summary: Get questions
|
||||
// produces:
|
||||
// - application/json
|
||||
// responses:
|
||||
// '200':
|
||||
// description: Questions
|
||||
// schema:
|
||||
// "$ref": "#/definitions/QuestionsResponse"
|
||||
// '500':
|
||||
// description: Failed to get questions
|
||||
|
||||
var params structs.LessonIdParam
|
||||
|
||||
if err := c.ParamsParser(¶ms); err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
// check if lesson belongs to organization
|
||||
|
||||
var lesson models.Lesson
|
||||
|
||||
if err := database.DB.Model(&models.Lesson{}).
|
||||
Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)).
|
||||
First(&lesson).Error; err != nil {
|
||||
return c.JSON([]models.Question{})
|
||||
}
|
||||
|
||||
// get questions
|
||||
|
||||
var questions []models.Question
|
||||
|
||||
if err := database.DB.Model(&models.Question{}).
|
||||
Where("lesson_id = ?", params.LessonId).
|
||||
Find(&questions).Error; err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
// get all questions liked by user
|
||||
|
||||
var likedQuestions []string
|
||||
|
||||
if err := database.DB.Model(&models.QuestionLike{}).
|
||||
Where("creator_user_id = ?", c.Locals("userId").(string)).
|
||||
Pluck("question_id", &likedQuestions).Error; err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
var questionLikes []models.QuestionLike
|
||||
|
||||
if err := database.DB.Model(&models.QuestionLike{}).
|
||||
Where("creator_user_id = ?", c.Locals("userId").(string)).
|
||||
Find(&questionLikes).Error; err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
var likedQuestions []string
|
||||
|
||||
for _, questionLike := range questionLikes {
|
||||
likedQuestions = append(likedQuestions, questionLike.QuestionId)
|
||||
} */
|
||||
|
||||
return c.JSON(structs.QuestionsResponse{
|
||||
Questions: questions,
|
||||
LikedQuestions: likedQuestions,
|
||||
})
|
||||
}
|
||||
|
||||
func CreateQuestion(c *fiber.Ctx) error {
|
||||
// swagger:operation POST /v1/lessons/{lessonId}/questions question createQuestion
|
||||
// ---
|
||||
// summary: Create question
|
||||
// consumes:
|
||||
// - application/json
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: body
|
||||
// in: body
|
||||
// schema:
|
||||
// "$ref": "#/definitions/CreateQuestionRequest"
|
||||
// responses:
|
||||
// '200':
|
||||
// description: Question created successfully
|
||||
// schema:
|
||||
// type: string
|
||||
// '400':
|
||||
// description: Invalid request body
|
||||
// '500':
|
||||
// description: Failed to create question
|
||||
|
||||
var params structs.LessonIdParam
|
||||
|
||||
if err := c.ParamsParser(¶ms); err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
var body structs.CreateQuestionRequest
|
||||
|
||||
if err := c.BodyParser(&body); err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
// check if lesson belongs to organization
|
||||
|
||||
var lesson models.Lesson
|
||||
|
||||
if err := database.DB.Model(&models.Lesson{}).
|
||||
Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)).
|
||||
First(&lesson).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
||||
// create question
|
||||
|
||||
question := models.Question{
|
||||
Id: uuid.New().String(),
|
||||
LessonId: params.LessonId,
|
||||
Message: body.Message,
|
||||
Likes: 0,
|
||||
CreatorUserId: c.Locals("userId").(string),
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
|
||||
if err := database.DB.Create(&question).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
socketclients.BroadcastMessageToTopic(
|
||||
c.Locals("organizationId").(string),
|
||||
utils.SubscribedTopicLessonsId(params.LessonId),
|
||||
structs.SendSocketMessage{
|
||||
Cmd: utils.SendCmdLessonQuestionCreated,
|
||||
Body: question,
|
||||
},
|
||||
)
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"status": "success",
|
||||
})
|
||||
}
|
||||
|
||||
func CreateQuestionReply(c *fiber.Ctx) error {
|
||||
// swagger:operation POST /v1/lessons/{lessonId}/questions/{questionId}/reply question createQuestionReply
|
||||
// ---
|
||||
// summary: Create question reply
|
||||
// consumes:
|
||||
// - application/json
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: body
|
||||
// in: body
|
||||
// schema:
|
||||
// "$ref": "#/definitions/CreateQuestionRequest"
|
||||
// responses:
|
||||
// '200':
|
||||
// description: Question reply created successfully
|
||||
// schema:
|
||||
// type: string
|
||||
// '400':
|
||||
// description: Invalid request body
|
||||
// '500':
|
||||
// description: Failed to create question reply
|
||||
|
||||
var params structs.LessonIdQuestionIdParam
|
||||
|
||||
if err := c.ParamsParser(¶ms); err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
var body structs.CreateQuestionRequest
|
||||
|
||||
if err := c.BodyParser(&body); err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
// check if lesson belongs to organization
|
||||
|
||||
var lesson models.Lesson
|
||||
|
||||
if err := database.DB.Model(&models.Lesson{}).
|
||||
Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)).
|
||||
First(&lesson).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
||||
// check if question belongs to lesson
|
||||
|
||||
var question models.Question
|
||||
|
||||
if err := database.DB.Model(&models.Question{}).
|
||||
Where("id = ? AND lesson_id = ?", params.QuestionId, params.LessonId).
|
||||
First(&question).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
||||
// create question reply
|
||||
|
||||
question = models.Question{
|
||||
Id: uuid.New().String(),
|
||||
LessonId: params.LessonId,
|
||||
QuestionId: params.QuestionId,
|
||||
ReplyId: params.QuestionId,
|
||||
Message: body.Message,
|
||||
Likes: 0,
|
||||
CreatorUserId: c.Locals("userId").(string),
|
||||
}
|
||||
|
||||
if err := database.DB.Create(&question).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
socketclients.BroadcastMessageToTopic(
|
||||
c.Locals("organizationId").(string),
|
||||
utils.SubscribedTopicLessonsId(params.LessonId),
|
||||
structs.SendSocketMessage{
|
||||
Cmd: utils.SendCmdLessonQuestionCreated,
|
||||
Body: question,
|
||||
},
|
||||
)
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"status": "success",
|
||||
})
|
||||
}
|
||||
|
||||
func LikeQuestion(c *fiber.Ctx) error {
|
||||
// swagger:operation POST /v1/lessons/{lessonId}/questions/{questionId}/likes question likeQuestion
|
||||
// ---
|
||||
// summary: Like question
|
||||
// produces:
|
||||
// - application/json
|
||||
// responses:
|
||||
// '200':
|
||||
// description: Question liked successfully
|
||||
// schema:
|
||||
// type: string
|
||||
// '500':
|
||||
// description: Failed to like question
|
||||
|
||||
var params structs.LessonIdQuestionIdParam
|
||||
|
||||
if err := c.ParamsParser(¶ms); err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
// check if lesson belongs to organization
|
||||
|
||||
var lesson models.Lesson
|
||||
|
||||
if err := database.DB.Model(&models.Lesson{}).
|
||||
Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)).
|
||||
First(&lesson).Error; err != nil {
|
||||
fmt.Println("lesson not found")
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
||||
// check if question belongs to lesson
|
||||
|
||||
var question models.Question
|
||||
|
||||
if err := database.DB.Model(&models.Question{}).
|
||||
Where("id = ? AND lesson_id = ?", params.QuestionId, params.LessonId).
|
||||
First(&question).Error; err != nil {
|
||||
fmt.Println("question not found")
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
||||
// check if user already liked question
|
||||
|
||||
var questionLike models.QuestionLike
|
||||
|
||||
if err := database.DB.Model(&models.QuestionLike{}).
|
||||
Where("question_id = ? AND creator_user_id = ?", params.QuestionId, c.Locals("userId").(string)).
|
||||
First(&questionLike).Error; err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
if questionLike.Id != "" {
|
||||
fmt.Println("question already liked")
|
||||
return c.SendStatus(fiber.StatusConflict)
|
||||
}
|
||||
|
||||
// like question
|
||||
|
||||
questionLike = models.QuestionLike{
|
||||
Id: uuid.New().String(),
|
||||
QuestionId: params.QuestionId,
|
||||
CreatorUserId: c.Locals("userId").(string),
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
|
||||
if err := database.DB.Create(&questionLike).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// update question likes
|
||||
|
||||
if err := database.DB.Model(&models.Question{}).
|
||||
Where("id = ?", params.QuestionId).
|
||||
Update("likes", gorm.Expr("likes + 1")).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// send message to user clients who liked the question
|
||||
socketclients.SendMessageToUserWithTopic(
|
||||
c.Locals("userId").(string),
|
||||
utils.SubscribedTopicLessonsId(params.LessonId),
|
||||
structs.SendSocketMessage{
|
||||
Cmd: utils.SendCmdLessonQuestionLiked,
|
||||
Body: question.Id,
|
||||
},
|
||||
)
|
||||
|
||||
// inform all users about the like
|
||||
socketclients.BroadcastMessageToTopic(
|
||||
c.Locals("userId").(string),
|
||||
utils.SubscribedTopicLessonsId(params.LessonId),
|
||||
structs.SendSocketMessage{
|
||||
Cmd: utils.SendCmdLessonQuestionCountUpLikes,
|
||||
Body: question.Id,
|
||||
},
|
||||
)
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"status": "success",
|
||||
})
|
||||
}
|
||||
|
||||
func DislikeQuestion(c *fiber.Ctx) error {
|
||||
// swagger:operation DELETE /v1/lessons/{lessonId}/questions/{questionId}/likes question dislikeQuestion
|
||||
// ---
|
||||
// summary: Dislike question
|
||||
// produces:
|
||||
// - application/json
|
||||
// responses:
|
||||
// '200':
|
||||
// description: Question disliked successfully
|
||||
// schema:
|
||||
// type: string
|
||||
// '500':
|
||||
// description: Failed to dislike question
|
||||
|
||||
var params structs.LessonIdQuestionIdParam
|
||||
|
||||
if err := c.ParamsParser(¶ms); err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
// check if lesson belongs to organization
|
||||
|
||||
var lesson models.Lesson
|
||||
|
||||
if err := database.DB.Model(&models.Lesson{}).
|
||||
Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)).
|
||||
First(&lesson).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
||||
// check if question belongs to lesson
|
||||
|
||||
var question models.Question
|
||||
|
||||
if err := database.DB.Model(&models.Question{}).
|
||||
Where("id = ? AND lesson_id = ?", params.QuestionId, params.LessonId).
|
||||
First(&question).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
||||
// check if user already liked question
|
||||
|
||||
var questionLike models.QuestionLike
|
||||
|
||||
if err := database.DB.Model(&models.QuestionLike{}).
|
||||
Where("question_id = ? AND creator_user_id = ?", params.QuestionId, c.Locals("userId").(string)).
|
||||
First(&questionLike).Error; err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
if questionLike.Id == "" {
|
||||
return c.SendStatus(fiber.StatusConflict)
|
||||
}
|
||||
|
||||
// dislike question
|
||||
|
||||
if err := database.DB.Delete(&questionLike).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// update question likes
|
||||
|
||||
if err := database.DB.Model(&models.Question{}).
|
||||
Where("id = ?", params.QuestionId).
|
||||
Update("likes", gorm.Expr("likes - 1")).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// send message to user clients who disliked the question
|
||||
socketclients.SendMessageToUserWithTopic(
|
||||
c.Locals("userId").(string),
|
||||
utils.SubscribedTopicLessonsId(params.LessonId),
|
||||
structs.SendSocketMessage{
|
||||
Cmd: utils.SendCmdLessonQuestionDisliked,
|
||||
Body: question.Id,
|
||||
},
|
||||
)
|
||||
|
||||
// inform all users about the dislike
|
||||
socketclients.BroadcastMessageToTopic(
|
||||
c.Locals("userId").(string),
|
||||
utils.SubscribedTopicLessonsId(params.LessonId),
|
||||
structs.SendSocketMessage{
|
||||
Cmd: utils.SendCmdLessonQuestionCountDownLikes,
|
||||
Body: question.Id,
|
||||
},
|
||||
)
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"status": "success",
|
||||
})
|
||||
}
|
|
@ -65,7 +65,9 @@ func GetRoles(c *fiber.Ctx) error {
|
|||
|
||||
var users []structs.HelperRoleUser
|
||||
|
||||
if err := database.DB.Model(&models.User{}).Where("role_id = ?", key).Where("organization_id = ?", c.Locals("organizationId").(string)).Find(&users).Error; err != nil {
|
||||
if err := database.DB.Model(&models.User{}).
|
||||
Where("role_id = ? AND organization_id = ?", key, c.Locals("organizationId").(string)).
|
||||
Find(&users).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,9 @@ func UpdateOrganizationSettings(c *fiber.Ctx) error {
|
|||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
if err := database.DB.Model(&models.Organization{}).Where("id = ?", c.Locals("organizationId").(string)).Updates(organizationSettings).Error; err != nil {
|
||||
if err := database.DB.Model(&models.Organization{}).
|
||||
Where("id = ?", c.Locals("organizationId").(string)).
|
||||
Updates(organizationSettings).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
@ -150,9 +152,10 @@ func UpdateOrganizationFile(c *fiber.Ctx) error {
|
|||
selectField = "banner_url"
|
||||
}
|
||||
|
||||
if err := database.DB.Model(&models.Organization{
|
||||
Id: c.Locals("organizationId").(string),
|
||||
}).Select(selectField).First(&organization).Error; err != nil {
|
||||
if err := database.DB.Model(&models.Organization{}).
|
||||
Where("id = ?", c.Locals("organizationId").(string)).
|
||||
Select(selectField).
|
||||
First(&organization).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
@ -180,7 +183,9 @@ func UpdateOrganizationFile(c *fiber.Ctx) error {
|
|||
update.BannerUrl = databasePath + fileName
|
||||
}
|
||||
|
||||
if err := database.DB.Model(&models.Organization{}).Where("id = ?", c.Locals("organizationId").(string)).Updates(update).Error; err != nil {
|
||||
if err := database.DB.Model(&models.Organization{}).
|
||||
Where("id = ?", c.Locals("organizationId").(string)).
|
||||
Updates(update).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
@ -241,7 +246,10 @@ func UpdateSubdomain(c *fiber.Ctx) error {
|
|||
|
||||
var organization models.Organization
|
||||
|
||||
if err := database.DB.Select("subdomain").Model(organization).Where("id = ?", c.Locals("organizationId").(string)).First(&organization).Error; err != nil {
|
||||
if err := database.DB.Select("subdomain").
|
||||
Model(organization).
|
||||
Where("id = ?", c.Locals("organizationId").(string)).
|
||||
First(&organization).Error; err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
@ -250,7 +258,9 @@ func UpdateSubdomain(c *fiber.Ctx) error {
|
|||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
if err := database.DB.Model(&organization).Where("id = ?", c.Locals("organizationId")).Update("subdomain", params.Subdomain).Error; err != nil {
|
||||
if err := database.DB.Model(&organization).
|
||||
Where("id = ?", c.Locals("organizationId")).
|
||||
Update("subdomain", params.Subdomain).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,9 @@ func GetTeamMembers(c *fiber.Ctx) error {
|
|||
|
||||
var users []structs.TeamMember
|
||||
|
||||
if err := database.DB.Model(&models.User{}).Where("organization_id = ?", c.Locals("organizationId")).Find(&users).Error; err != nil {
|
||||
if err := database.DB.Model(&models.User{}).
|
||||
Where("organization_id = ?", c.Locals("organizationId")).
|
||||
Find(&users).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
@ -176,8 +178,7 @@ func UpdateTeamMemberRole(c *fiber.Ctx) error {
|
|||
}
|
||||
|
||||
if err := database.DB.Model(&models.User{}).
|
||||
Where("id = ?", params.MemberId).
|
||||
Where("organization_id = ?", c.Locals("organizationId").(string)).
|
||||
Where("id = ? AND organization_id = ?", params.MemberId, c.Locals("organizationId").(string)).
|
||||
Update("role_id", body.RoleId).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
|
|
@ -62,7 +62,8 @@ func UserLogin(c *fiber.Ctx) error {
|
|||
|
||||
organizationId := c.Locals("organizationId").(string)
|
||||
|
||||
if err := database.DB.Select("id", "disabled", "password").First(&user, "email = ? AND organization_id = ?", body.Email, organizationId).Error; err != nil {
|
||||
if err := database.DB.Select("id", "disabled", "password").
|
||||
First(&user, "email = ? AND organization_id = ?", body.Email, organizationId).Error; err != nil {
|
||||
logger.AddSystemLog(rslogger.LogTypeError, "Failed to find user with email %s", body.Email)
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
|
|
@ -32,7 +32,10 @@ func GetUserProfile(c *fiber.Ctx) error {
|
|||
|
||||
var user structs.GetUserProfileResponse
|
||||
|
||||
database.DB.Model(&models.User{}).Where("id = ?", c.Locals("userId").(string)).First(&user)
|
||||
database.DB.Model(&models.User{}).
|
||||
Select("email", "first_name", "last_name", "profile_picture_url", "role_id").
|
||||
Where("id = ?", c.Locals("userId").(string)).
|
||||
First(&user)
|
||||
|
||||
return c.JSON(user)
|
||||
}
|
||||
|
@ -78,7 +81,10 @@ func UpdateUserProfilePicture(c *fiber.Ctx) error {
|
|||
|
||||
user := models.User{}
|
||||
|
||||
if err := database.DB.Model(&models.User{}).Select("profile_picture_url").Where("id = ?", c.Locals("userId").(string)).First(&user).Error; err != nil {
|
||||
if err := database.DB.Model(&models.User{}).
|
||||
Select("profile_picture_url").
|
||||
Where("id = ?", c.Locals("userId").(string)).
|
||||
First(&user).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
@ -96,7 +102,9 @@ func UpdateUserProfilePicture(c *fiber.Ctx) error {
|
|||
|
||||
profilePictureUrl := databasePath + fileName
|
||||
|
||||
if err := database.DB.Model(&models.User{}).Where("id = ?", c.Locals("userId").(string)).Update("profile_picture_url", profilePictureUrl).Error; err != nil {
|
||||
if err := database.DB.Model(&models.User{}).
|
||||
Where("id = ?", c.Locals("userId").(string)).
|
||||
Update("profile_picture_url", profilePictureUrl).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
|
@ -120,3 +128,46 @@ func UpdateUserProfilePicture(c *fiber.Ctx) error {
|
|||
"Data": databasePath + fileName,
|
||||
})
|
||||
}
|
||||
|
||||
func GetUser(c *fiber.Ctx) error {
|
||||
// swagger:operation GET /user/{userId} user getUser
|
||||
// ---
|
||||
// summary: Get user
|
||||
// consumes:
|
||||
// - application/json
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: userId
|
||||
// in: path
|
||||
// type: string
|
||||
// required: true
|
||||
// responses:
|
||||
// '200':
|
||||
// description: User fetched successfully
|
||||
// schema:
|
||||
// "$ref": "#/definitions/GetUserResponse"
|
||||
// '400':
|
||||
// description: Invalid request body
|
||||
// '404':
|
||||
// description: User not found
|
||||
// '500':
|
||||
// description: Failed to fetch user
|
||||
|
||||
var params structs.UserIdParam
|
||||
|
||||
if err := c.ParamsParser(¶ms); err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
var user structs.GetUserResponse
|
||||
|
||||
if err := database.DB.Model(&models.User{}).
|
||||
Select("id", "first_name", "last_name", "profile_picture_url").
|
||||
Where("id = ? AND organization_id = ?", params.UserId, c.Locals("organizationId").(string)).
|
||||
First(&user).Error; err != nil {
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
||||
return c.JSON(user)
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ func SetupRoutes(app *fiber.App) {
|
|||
u.Post("/auth/login", handleOrganizationSubdomain, user.UserLogin)
|
||||
u.Get("/profile", handleOrganizationSubdomain, requestAccessValidation, user.GetUserProfile)
|
||||
u.Post("/profile/picture", handleOrganizationSubdomain, requestAccessValidation, user.UpdateUserProfilePicture)
|
||||
u.Get("/:userId", handleOrganizationSubdomain, requestAccessValidation, user.GetUser)
|
||||
|
||||
l := v1.Group("/lessons")
|
||||
l.Get("/", handleOrganizationSubdomain, requestAccessValidation, lessons.GetLessons)
|
||||
|
@ -51,6 +52,11 @@ func SetupRoutes(app *fiber.App) {
|
|||
l.Patch("/:lessonId/contents/:contentId/position", handleOrganizationSubdomain, requestAccessValidation, lessons.UpdateLessonContentPosition)
|
||||
l.Delete("/:lessonId/contents/:contentId", handleOrganizationSubdomain, requestAccessValidation, lessons.DeleteLessonContent)
|
||||
l.Post("/:lessonId/contents/:contentId/file/:type", handleOrganizationSubdomain, requestAccessValidation, lessons.UploadLessonContentFile)
|
||||
l.Get("/:lessonId/questions", handleOrganizationSubdomain, requestAccessValidation, lessons.GetQuestions)
|
||||
l.Post("/:lessonId/questions", handleOrganizationSubdomain, requestAccessValidation, lessons.CreateQuestion)
|
||||
l.Post("/:lessonId/questions/:questionId/replies", handleOrganizationSubdomain, requestAccessValidation, lessons.CreateQuestionReply)
|
||||
l.Post("/:lessonId/questions/:questionId/likes", handleOrganizationSubdomain, requestAccessValidation, lessons.LikeQuestion)
|
||||
l.Delete("/:lessonId/questions/:questionId/likes", handleOrganizationSubdomain, requestAccessValidation, lessons.DislikeQuestion)
|
||||
|
||||
app.Static("/static", config.Cfg.FolderPaths.PublicStatic)
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ func BroadcastMessageToTopics(organizationId string, topics []string, sendSocket
|
|||
}
|
||||
|
||||
func hasClientSubscribedToTopic(topic string, clientTopic string) bool {
|
||||
return clientTopic == topic || strings.HasPrefix(clientTopic, topic)
|
||||
return clientTopic == topic /* || strings.HasPrefix(clientTopic, topic) */
|
||||
}
|
||||
|
||||
// Used to determine if a user is connected regardless of the session used
|
||||
|
@ -93,3 +93,11 @@ func SendMessageToUserWithTopicExceptBrowserTabSession(userId string, topic stri
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SendMessageToUserWithTopic(userId string, topic string, sendSocketMessage structs.SendSocketMessage) {
|
||||
for _, client := range cache.GetSocketClients() {
|
||||
if client.UserId == userId && client.SubscribedTopic == topic {
|
||||
client.SendMessage(sendSocketMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue