diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..547f3f9 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,27 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch file", + "type": "go", + "request": "launch", + "mode": "debug", + "program": "backend/main.go", + "args": ["serve"], + "showLog": true + }, + { + "name": "Launch Package", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "backend", + "env": {}, + "args": ["serve"], + "showLog": true + } + ] +} diff --git a/backend/Dockerfile b/backend/Dockerfile index 77f2aca..67a9d42 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.20.5-alpine +FROM golang:1.21.3-alpine # Set the Current Working Directory inside the container WORKDIR /app diff --git a/backend/go.mod b/backend/go.mod index 0d8e6d3..660cc3d 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -1,8 +1,9 @@ module htwkalender -go 1.20 +go 1.21.3 require ( + github.com/google/uuid v1.3.1 github.com/jordic/goics v0.0.0-20210404174824-5a0337b716a0 github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61 github.com/pocketbase/dbx v1.10.1 @@ -13,13 +14,13 @@ require ( require ( github.com/AlecAivazis/survey/v2 v2.3.7 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/aws/aws-sdk-go v1.45.25 // indirect + github.com/aws/aws-sdk-go v1.46.3 // indirect github.com/aws/aws-sdk-go-v2 v1.21.2 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.14 // indirect - github.com/aws/aws-sdk-go-v2/config v1.18.45 // indirect + github.com/aws/aws-sdk-go-v2/config v1.19.1 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.13.43 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 // indirect - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.90 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.92 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45 // indirect @@ -44,14 +45,13 @@ require ( github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/google/uuid v1.3.1 // indirect github.com/google/wire v0.5.0 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect @@ -73,16 +73,15 @@ require ( golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.14.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect - google.golang.org/api v0.147.0 // indirect + google.golang.org/api v0.148.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a // indirect - google.golang.org/grpc v1.58.3 // indirect - google.golang.org/protobuf v1.31.0 //indirect - gopkg.in/yaml.v2 v2.4.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect + google.golang.org/grpc v1.59.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect lukechampine.com/uint128 v1.3.0 // indirect modernc.org/cc/v3 v3.41.0 // indirect modernc.org/ccgo/v3 v3.16.15 // indirect - modernc.org/libc v1.24.1 // indirect + modernc.org/libc v1.28.0 // indirect modernc.org/mathutil v1.6.0 // indirect modernc.org/memory v1.7.2 // indirect modernc.org/opt v0.1.3 // indirect diff --git a/backend/go.sum b/backend/go.sum index f7408c9..cdbecb5 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -1,9 +1,14 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o= +cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= +cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= cloud.google.com/go/storage v1.31.0 h1:+S3LjjEN2zZ+L5hOwj4+1OkGCsLVe0NzpXKQ1pSdTCI= +cloud.google.com/go/storage v1.31.0/go.mod h1:81ams1PrhW16L4kF7qg+4mTq7SRs5HsbDTM0bWvrwJ0= github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -12,20 +17,20 @@ github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDe github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4= -github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.46.3 h1:zcrCu14ANOji6m38bUTxYdPqne4EXIvJQ2KXZ5oi9k0= +github.com/aws/aws-sdk-go v1.46.3/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v1.21.2 h1:+LXZ0sgo8quN9UOKXXzAWRT3FWd4NxeXWOZom9pE7GA= github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.14 h1:Sc82v7tDQ/vdU1WtuSyzZ1I7y/68j//HJ6uozND1IDs= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.14/go.mod h1:9NCTOURS8OpxvoAVHq79LK81/zC78hfRWFn+aL0SPcY= -github.com/aws/aws-sdk-go-v2/config v1.18.45 h1:Aka9bI7n8ysuwPeFdm77nfbyHCAKQ3z9ghB3S/38zes= -github.com/aws/aws-sdk-go-v2/config v1.18.45/go.mod h1:ZwDUgFnQgsazQTnWfeLWk5GjeqTQTL8lMkoE1UXzxdE= +github.com/aws/aws-sdk-go-v2/config v1.19.1 h1:oe3vqcGftyk40icfLymhhhNysAwk0NfiwkDi2GTPMXs= +github.com/aws/aws-sdk-go-v2/config v1.19.1/go.mod h1:ZwDUgFnQgsazQTnWfeLWk5GjeqTQTL8lMkoE1UXzxdE= github.com/aws/aws-sdk-go-v2/credentials v1.13.43 h1:LU8vo40zBlo3R7bAvBVy/ku4nxGEyZe9N8MqAeFTzF8= github.com/aws/aws-sdk-go-v2/credentials v1.13.43/go.mod h1:zWJBz1Yf1ZtX5NGax9ZdNjhhI4rgjfgsyk6vTY1yfVg= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 h1:PIktER+hwIG286DqXyvVENjgLTAwGgoeriLDD5C+YlQ= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13/go.mod h1:f/Ib/qYjhV2/qdsf79H3QP/eRE4AkVyEf6sk7XfZ1tg= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.90 h1:mtJRt80k1oGw7QQPluAx8AZ6u16MyCA2di/lMhagZ7I= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.90/go.mod h1:lYwZTkeMQWPvNU+u7oYArdNhQ8EKiSGU76jVv0w2GH4= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.92 h1:nLA7dGFC6v4P6b+hzqt5GqIGmIuN+jTJzojfdOLXWFE= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.92/go.mod h1:h+ei9z19AhoN+Dac92DwkzfbJ4mFUea92xgl5pKSG0Q= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 h1:nFBQlGtkbPzp/NjZLuFxRqmT91rLJkgvsEQs68h962Y= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43/go.mod h1:auo+PiyLl0n1l8A0e8RIeR8tOzYPfZZH/JNlrJ8igTQ= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 h1:JRVhO25+r3ar2mKGP7E0LDl8K9/G36gjlqca5iQbaqc= @@ -74,6 +79,7 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 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/ganigeorgiev/fexpr v0.3.0 h1:RwSyJBME+g/XdzlUW0paH/4VXhLHPg+rErtLeC7K8Ew= @@ -83,6 +89,7 @@ github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRi github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= +github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= @@ -114,12 +121,18 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-replayers/grpcreplay v1.1.0 h1:S5+I3zYyZ+GQz68OfbURDdt/+cSMqCK1wrvNx7WBzTE= +github.com/google/go-replayers/grpcreplay v1.1.0/go.mod h1:qzAvJ8/wi57zq7gWqaE6AwLM6miiXUQwP1S+I9icmhk= github.com/google/go-replayers/httpreplay v1.2.0 h1:VM1wEyyjaoU53BwrOnaf9VhAyQQEEioJvFYxYcLRKzk= +github.com/google/go-replayers/httpreplay v1.2.0/go.mod h1:WahEFFZZ7a1P4VM1qEeHy+tME4bwyqPcwWbNlUI1Mcg= github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20230912144702-c363fe2c2ed8 h1:gpptm606MZYGaMHMsB4Srmb6EbW/IVHnt04rcMXnkBQ= +github.com/google/pprof v0.0.0-20230912144702-c363fe2c2ed8/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= @@ -127,6 +140,7 @@ github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= +github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= @@ -144,7 +158,9 @@ github.com/jordic/goics v0.0.0-20210404174824-5a0337b716a0/go.mod h1:YHaw6sOIeFR github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61 h1:FwuzbVh87iLiUQj1+uQUsuw9x5t9m5n5g7rG7o4svW4= github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61/go.mod h1:paQfF1YtHe+GrGg5fOgjsjoCX/UKDr9bc1DoWpZfns8= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -153,8 +169,8 @@ github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxec github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -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-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= @@ -172,6 +188,7 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= @@ -188,6 +205,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 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/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= @@ -277,8 +295,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -google.golang.org/api v0.147.0 h1:Can3FaQo9LlVqxJCodNmeZW/ib3/qKAY3rFeXiHo5gc= -google.golang.org/api v0.147.0/go.mod h1:pQ/9j83DcmPd/5C9e2nFOdjjNkDZ1G+zkbK2uvdkJMs= +google.golang.org/api v0.148.0 h1:HBq4TZlN4/1pNcu0geJZ/Q50vIwIXT532UIMYoo0vOs= +google.golang.org/api v0.148.0/go.mod h1:8/TBgwaKjfqTdacOJrOv2+2Q6fBDU1uHKK06oGSkxzU= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= @@ -287,17 +305,19 @@ google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0= +google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a h1:fwgW9j3vHirt4ObdHoYNwuO24BEZjSzbh+zPaNWoiY8= +google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:EMfReVxb80Dq1hhioy0sOsY9jCE46YDgHlJ7fWVUWRE= google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 h1:W18sezcAYs+3tDZX4F80yctqa12jcP1PUS2gQu1zTPU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a h1:a2MQQVoTo96JC9PMGtGBymLp7+/RzpFc2yX/9WfFg1c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= +google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -313,9 +333,8 @@ google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 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= @@ -328,9 +347,11 @@ modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y= modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0= modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI= modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= -modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= -modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v1.28.0 h1:kHB6LtDBV8DEAK7aZT1vWvP92abW9fb8cjb1P9UTpUE= +modernc.org/libc v1.28.0/go.mod h1:DaG/4Q3LRRdqpiLyP0C2m1B8ZMGkQ+cCgOIjEtQlYhQ= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= @@ -342,6 +363,8 @@ modernc.org/sqlite v1.26.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY= +modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY= +modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE= diff --git a/backend/migrations/1698017941_updated_events.go b/backend/migrations/1698017941_updated_events.go new file mode 100644 index 0000000..b7d0680 --- /dev/null +++ b/backend/migrations/1698017941_updated_events.go @@ -0,0 +1,52 @@ +package migrations + +import ( + "encoding/json" + + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/daos" + m "github.com/pocketbase/pocketbase/migrations" + "github.com/pocketbase/pocketbase/models/schema" +) + +func init() { + m.Register(func(db dbx.Builder) error { + dao := daos.New(db) + + collection, err := dao.FindCollectionByNameOrId("7her4515qsmrxe8") + if err != nil { + return err + } + + // add + new_uuid := &schema.SchemaField{} + json.Unmarshal([]byte(`{ + "system": false, + "id": "0kahthzr", + "name": "uuid", + "type": "text", + "required": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }`), new_uuid) + collection.Schema.AddField(new_uuid) + + return dao.SaveCollection(collection) + }, func(db dbx.Builder) error { + dao := daos.New(db) + + collection, err := dao.FindCollectionByNameOrId("7her4515qsmrxe8") + if err != nil { + return err + } + + // remove + collection.Schema.RemoveField("0kahthzr") + + return dao.SaveCollection(collection) + }) +} diff --git a/backend/model/eventModel.go b/backend/model/eventModel.go index daaf229..5daf446 100644 --- a/backend/model/eventModel.go +++ b/backend/model/eventModel.go @@ -1,8 +1,18 @@ package model -type Events []*Event +import ( + "github.com/pocketbase/pocketbase/models" + "slices" +) + +type Events []Event + +func (m Events) Contains(event Event) bool { + return slices.Contains(m, event) +} type Event struct { + UUID string `db:"uuid" json:"uuid"` Day string `db:"Day" json:"day"` Week string `db:"Week" json:"week"` Start string `db:"Start" json:"start"` @@ -15,4 +25,27 @@ type Event struct { BookedAt string `db:"BookedAt" json:"bookedAt"` Course string `db:"course" json:"course"` Semester string `db:"semester" json:"semester"` + models.BaseModel +} + +func (m *Event) Equals(event Event) bool { + return m.Day == event.Day && + m.Week == event.Week && + m.Start == event.Start && + m.End == event.End && + m.Name == event.Name && + m.Course == event.Course && + m.Prof == event.Prof && + m.Rooms == event.Rooms && + m.EventType == event.EventType +} + +func (m *Event) TableName() string { + return "events" +} + +// SetCourse func to set the course and returns the event +func (m *Event) SetCourse(course string) Event { + m.Course = course + return *m } diff --git a/backend/model/eventModel_test.go b/backend/model/eventModel_test.go new file mode 100644 index 0000000..d73c109 --- /dev/null +++ b/backend/model/eventModel_test.go @@ -0,0 +1,126 @@ +package model + +import ( + "github.com/pocketbase/pocketbase/models" + "testing" +) + +func TestEvents_Contains(t *testing.T) { + type args struct { + event Event + } + tests := []struct { + name string + m Events + args args + want bool + }{ + { + name: "empty events", + m: Events{}, + args: args{event: Event{}}, + want: false, + }, + { + name: "one event", + m: Events{{Day: "test", Week: "test", Start: "test", End: "test", Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}}, + args: args{event: Event{Day: "test", Week: "test", Start: "test", End: "test", Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}}, + want: true, + }, + { + name: "two events", + m: Events{{Day: "test", Week: "test", Start: "test", End: "test", Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}, {Day: "test2", Week: "test2", Start: "test2", End: "test2", Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2"}}, + args: args{event: Event{Day: "test2", Week: "test2", Start: "test2", End: "test2", Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2"}}, + want: true, + }, + { + name: "two events with different values", + m: Events{{Day: "test", Week: "test", Start: "test", End: "test", Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test", UUID: "439ßu56rf8u9ijn4f4-2345345"}, {Day: "test2", Week: "test2", Start: "test2", End: "test2", Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2", UUID: "432a39ßu545349ijn4f4-23dsa45"}}, + args: args{event: Event{Day: "test3", Week: "test3", Start: "test3", End: "test3", Name: "test3", Course: "test3", Prof: "test3", Rooms: "test3", EventType: "test3", UUID: "934mf43r34f-g68h7655tg3"}}, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.m.Contains(tt.args.event); got != tt.want { + t.Errorf("Contains() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestEvent_Equals(t *testing.T) { + type fields struct { + UUID string + Day string + Week string + Start string + End string + Name string + EventType string + Prof string + Rooms string + Notes string + BookedAt string + Course string + Semester string + BaseModel models.BaseModel + } + type args struct { + event Event + } + tests := []struct { + name string + fields fields + args args + want bool + }{ + { + name: "empty events", + fields: fields{}, + args: args{event: Event{}}, + want: true, + }, + { + name: "one empty one not", + fields: fields{Day: "test", Week: "test", Start: "test", End: "test", Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}, + args: args{event: Event{}}, + want: false, + }, + { + name: "one event", + fields: fields{Day: "test", Week: "test", Start: "test", End: "test", Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}, + args: args{event: Event{Day: "test", Week: "test", Start: "test", End: "test", Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}}, + want: true, + }, + { + name: "two events", + fields: fields{Day: "test", Week: "test", Start: "test", End: "test", Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}, + args: args{event: Event{Day: "test2", Week: "test2", Start: "test2", End: "test2", Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2"}}, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Event{ + UUID: tt.fields.UUID, + Day: tt.fields.Day, + Week: tt.fields.Week, + Start: tt.fields.Start, + End: tt.fields.End, + Name: tt.fields.Name, + EventType: tt.fields.EventType, + Prof: tt.fields.Prof, + Rooms: tt.fields.Rooms, + Notes: tt.fields.Notes, + BookedAt: tt.fields.BookedAt, + Course: tt.fields.Course, + Semester: tt.fields.Semester, + BaseModel: tt.fields.BaseModel, + } + if got := m.Equals(tt.args.event); got != tt.want { + t.Errorf("Equals() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/backend/model/feedModel.go b/backend/model/feedModel.go index 0f2cb35..e3920a2 100644 --- a/backend/model/feedModel.go +++ b/backend/model/feedModel.go @@ -1,8 +1,13 @@ package model +import "github.com/pocketbase/pocketbase/models" + type Feed struct { - Id string `db:"id" json:"id"` Modules string `db:"modules" json:"modules"` - Created string `db:"created" json:"created"` - Updated string `db:"updated" json:"updated"` + models.BaseModel +} + +// SetModules set modules field +func (f *Feed) SetModules(modules string) { + f.Modules = modules } diff --git a/backend/model/icalModel.go b/backend/model/icalModel.go index 192a528..2060712 100644 --- a/backend/model/icalModel.go +++ b/backend/model/icalModel.go @@ -23,6 +23,7 @@ type Entry struct { type Entries []*Entry type FeedCollection struct { + UUID string `db:"uuid" json:"uuid"` Name string `db:"Name" json:"name"` Course string `db:"course" json:"course"` UserDefinedName string `db:"userDefinedName" json:"userDefinedName"` diff --git a/backend/model/moduleModel.go b/backend/model/moduleModel.go index ab0d17f..422613d 100644 --- a/backend/model/moduleModel.go +++ b/backend/model/moduleModel.go @@ -1,6 +1,7 @@ package model type Module struct { + UUID string `json:"uuid"` Name string `json:"name"` Prof string `json:"prof"` Course string `json:"course"` diff --git a/backend/pb_schema.json b/backend/pb_schema.json index d3536f9..2054fd0 100644 --- a/backend/pb_schema.json +++ b/backend/pb_schema.json @@ -1,172 +1,4 @@ [ - { - "id": "_pb_users_auth_", - "name": "users", - "type": "auth", - "system": false, - "schema": [ - { - "id": "users_name", - "name": "name", - "type": "text", - "system": false, - "required": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "id": "users_avatar", - "name": "avatar", - "type": "file", - "system": false, - "required": false, - "options": { - "maxSelect": 1, - "maxSize": 5242880, - "mimeTypes": [ - "image/jpeg", - "image/png", - "image/svg+xml", - "image/gif", - "image/webp" - ], - "thumbs": null, - "protected": false - } - } - ], - "indexes": [], - "listRule": "id = @request.auth.id", - "viewRule": "id = @request.auth.id", - "createRule": "", - "updateRule": "id = @request.auth.id", - "deleteRule": "id = @request.auth.id", - "options": { - "allowEmailAuth": true, - "allowOAuth2Auth": true, - "allowUsernameAuth": true, - "exceptEmailDomains": null, - "manageRule": null, - "minPasswordLength": 8, - "onlyEmailDomains": null, - "requireEmail": false - } - }, - { - "id": "cfq9mqlmd97v8z5", - "name": "groups", - "type": "base", - "system": false, - "schema": [ - { - "id": "85msl21p", - "name": "university", - "type": "text", - "system": false, - "required": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "id": "2sii4dtp", - "name": "shortcut", - "type": "text", - "system": false, - "required": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "id": "uiwgo28f", - "name": "groupId", - "type": "text", - "system": false, - "required": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "id": "y0l1lrzs", - "name": "course", - "type": "text", - "system": false, - "required": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "id": "kr62mhbz", - "name": "faculty", - "type": "text", - "system": false, - "required": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "id": "ya6znpez", - "name": "facultyId", - "type": "text", - "system": false, - "required": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - } - ], - "indexes": [ - "CREATE UNIQUE INDEX `idx_rcaN2Oq` ON `groups` (`course`)" - ], - "listRule": null, - "viewRule": null, - "createRule": null, - "updateRule": null, - "deleteRule": null, - "options": {} - }, - { - "id": "d65h4wh7zk13gxp", - "name": "feeds", - "type": "base", - "system": false, - "schema": [ - { - "id": "cowxjfmc", - "name": "modules", - "type": "json", - "system": false, - "required": true, - "options": {} - } - ], - "indexes": [], - "listRule": null, - "viewRule": null, - "createRule": null, - "updateRule": null, - "deleteRule": null, - "options": {} - }, { "id": "7her4515qsmrxe8", "name": "events", diff --git a/backend/service/addRoute.go b/backend/service/addRoute.go index 0d20902..aaf7f1c 100644 --- a/backend/service/addRoute.go +++ b/backend/service/addRoute.go @@ -5,23 +5,17 @@ import ( "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/apis" "github.com/pocketbase/pocketbase/core" + "htwkalender/model" "htwkalender/service/events" "htwkalender/service/fetch" "htwkalender/service/ical" "htwkalender/service/room" "io" "net/http" - "net/url" - "os" ) func AddRoutes(app *pocketbase.PocketBase) { - app.OnBeforeServe().Add(func(e *core.ServeEvent) error { - e.Router.GET("/*", apis.StaticDirectoryHandler(os.DirFS("./pb_public"), false)) - return nil - }) - app.OnBeforeServe().Add(func(e *core.ServeEvent) error { _, err := e.Router.AddRoute(echo.Route{ Method: http.MethodGet, @@ -39,6 +33,24 @@ func AddRoutes(app *pocketbase.PocketBase) { return nil }) + app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + _, err := e.Router.AddRoute(echo.Route{ + Method: http.MethodDelete, + Path: "/api/modules", + Handler: func(c echo.Context) error { + return events.DeleteAllEvents(app) + }, + Middlewares: []echo.MiddlewareFunc{ + apis.ActivityLogger(app), + apis.RequireAdminAuth(), + }, + }) + if err != nil { + return err + } + return nil + }) + app.OnBeforeServe().Add(func(e *core.ServeEvent) error { _, err := e.Router.AddRoute(echo.Route{ Method: http.MethodGet, @@ -199,12 +211,17 @@ func AddRoutes(app *pocketbase.PocketBase) { app.OnBeforeServe().Add(func(e *core.ServeEvent) error { _, err := e.Router.AddRoute(echo.Route{ - Method: http.MethodGet, + Method: http.MethodPost, Path: "/api/module", Handler: func(c echo.Context) error { - name := c.Request().Header.Get("Name") - name, err := url.QueryUnescape(name) - module, err := events.GetModuleByName(app, name) + + var requestModule model.Module + + if err := c.Bind(&requestModule); err != nil { + return apis.NewBadRequestError("Failed to read request body", err) + } + + module, err := events.GetModuleByName(app, requestModule) if err != nil { return c.JSON(400, err) @@ -263,4 +280,28 @@ func AddRoutes(app *pocketbase.PocketBase) { } return nil }) + + app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + _, err := e.Router.AddRoute(echo.Route{ + Method: http.MethodGet, + Path: "/api/feed/migrate", + Handler: func(c echo.Context) error { + err := ical.MigrateFeedJson(app) + + if err != nil { + return c.JSON(500, err) + } else { + return c.JSON(200, "Migrated") + } + }, + Middlewares: []echo.MiddlewareFunc{ + apis.ActivityLogger(app), + apis.RequireAdminAuth(), + }, + }) + if err != nil { + return err + } + return nil + }) } diff --git a/backend/service/db/dbEvents.go b/backend/service/db/dbEvents.go index f763260..5358051 100644 --- a/backend/service/db/dbEvents.go +++ b/backend/service/db/dbEvents.go @@ -3,78 +3,81 @@ package db import ( "github.com/pocketbase/dbx" "github.com/pocketbase/pocketbase" - "github.com/pocketbase/pocketbase/models" "htwkalender/model" - "log" ) -func SaveEvents(seminarGroup []model.SeminarGroup, collection *models.Collection, app *pocketbase.PocketBase) ([]*models.Record, error) { - var toBeSavedEvents []struct { - model.Event - string - } - var savedRecords []*models.Record - var insertRecords []*models.Record +func SaveEvents(seminarGroup []model.SeminarGroup, app *pocketbase.PocketBase) ([]model.Event, error) { + var toBeSavedEvents model.Events + var savedRecords model.Events // check if event is already in database and add to toBeSavedEvents if not for _, seminarGroup := range seminarGroup { for _, event := range seminarGroup.Events { - dbGroup, err := findEventByDayWeekStartEndNameCourse(event, seminarGroup.Course, app) + event = event.SetCourse(seminarGroup.Course) + existsInDatabase, err := findEventByDayWeekStartEndNameCourse(event, seminarGroup.Course, app) + alreadyAddedToSave := toBeSavedEvents.Contains(event) - if dbGroup == nil && err.Error() == "sql: no rows in result set" { - toBeSavedEvents = append(toBeSavedEvents, struct { - model.Event - string - }{event, seminarGroup.Course}) - } else if err != nil { + if err != nil { return nil, err } + + if !existsInDatabase && !alreadyAddedToSave { + toBeSavedEvents = append(toBeSavedEvents, event) + } } } // create record for each event that's not already in the database for _, event := range toBeSavedEvents { - record := models.NewRecord(collection) - record.Set("Day", event.Day) - record.Set("Week", event.Week) - record.Set("Start", event.Start) - record.Set("End", event.End) - record.Set("Name", event.Name) - record.Set("EventType", event.EventType) - record.Set("Prof", event.Prof) - record.Set("Rooms", event.Rooms) - record.Set("Notes", event.Notes) - record.Set("BookedAt", event.BookedAt) - record.Set("course", event.string) - record.Set("semester", event.Semester) - insertRecords = append(insertRecords, record) - } - - // save all records - for _, record := range insertRecords { - if record != nil { - err := app.Dao().SaveRecord(record) - if err == nil { - savedRecords = append(savedRecords, record) - } else { - log.Println("Error while saving record: ", err) - return nil, err - } + event.MarkAsNew() + // auto mapping for event fields to record fields + err := app.Dao().Save(&event) + if err != nil { + return nil, err + } else { + savedRecords = append(savedRecords, event) } } return savedRecords, nil } -func findEventByDayWeekStartEndNameCourse(event model.Event, course string, app *pocketbase.PocketBase) (*model.Event, error) { - err := app.Dao().DB().Select("*").From("events").Where( - dbx.NewExp("Day = {:day} AND Week = {:week} AND Start = {:start} AND End = {:end} AND Name = {:name} AND course = {:course} AND Prof = {:prof} AND Rooms = {:rooms} AND EventType = {:eventType}", - dbx.Params{"day": event.Day, "week": event.Week, "start": event.Start, "end": event.End, "name": event.Name, "course": course, "prof": event.Prof, "rooms": event.Rooms, "eventType": event.EventType}), - ).One(&event) +// check if event is already in database and return true if it is and false if it's not +func findEventByDayWeekStartEndNameCourse(event model.Event, course string, app *pocketbase.PocketBase) (bool, error) { + + var dbEvent model.Event + + err := app.Dao().DB().Select("*").From("events"). + Where(dbx.NewExp( + "Day = {:day} AND "+ + "Week = {:week} AND "+ + "Start = {:start} AND "+ + "End = {:end} AND "+ + "Name = {:name} AND "+ + "course = {:course} AND "+ + "Prof = {:prof} AND "+ + "Rooms = {:rooms} AND "+ + "EventType = {:eventType}", + dbx.Params{ + "day": event.Day, + "week": event.Week, + "start": event.Start, + "end": event.End, + "name": event.Name, + "course": course, + "prof": event.Prof, + "rooms": event.Rooms, + "eventType": event.EventType}), + ).One(&dbEvent) + if err != nil { - return nil, err + if err.Error() == "sql: no rows in result set" { + return false, nil + } + return false, err + } else { + return true, nil } - return &event, err } func buildIcalQueryForModules(modules []model.FeedCollection) dbx.Expression { @@ -176,10 +179,21 @@ func DeleteAllEventsForCourse(app *pocketbase.PocketBase, course string, semeste return nil } -func FindAllEventsByModule(app *pocketbase.PocketBase, moduleName string) (model.Events, error) { +func DeleteAllEvents(app *pocketbase.PocketBase) error { + + _, err := app.Dao().DB().Delete("events", dbx.NewExp("1=1")).Execute() + + if err != nil { + return err + } + + return nil +} + +func FindAllEventsByModule(app *pocketbase.PocketBase, module model.Module) (model.Events, error) { var events model.Events - err := app.Dao().DB().Select("*").From("events").Where(dbx.NewExp("Name = {:moduleName}", dbx.Params{"moduleName": moduleName})).All(&events) + err := app.Dao().DB().Select("*").From("events").Where(dbx.NewExp("Name = {:moduleName} AND course = {:course}", dbx.Params{"moduleName": module.Name, "course": module.Course})).All(&events) if err != nil { print("Error while getting events from database: ", err) return nil, err diff --git a/backend/service/events/eventService.go b/backend/service/events/eventService.go index 450ae43..4b646da 100644 --- a/backend/service/events/eventService.go +++ b/backend/service/events/eventService.go @@ -46,14 +46,15 @@ func GetAllModulesDistinct(app *pocketbase.PocketBase, c echo.Context) error { // If the module does not exist, an error is returned // If the module exists, the module is returned // Module is a struct that exists in database as events -func GetModuleByName(app *pocketbase.PocketBase, name string) (model.Module, error) { - events, err := db.FindAllEventsByModule(app, name) +func GetModuleByName(app *pocketbase.PocketBase, module model.Module) (model.Module, error) { + events, err := db.FindAllEventsByModule(app, module) if err != nil || len(events) == 0 { return model.Module{}, err } else { return model.Module{ - Name: name, + UUID: events[0].UUID, + Name: events[0].Name, Events: events, Prof: events[0].Prof, Course: events[0].Course, @@ -74,6 +75,15 @@ func DeleteAllEventsByCourseAndSemester(app *pocketbase.PocketBase, course strin } } +func DeleteAllEvents(app *pocketbase.PocketBase) error { + err := db.DeleteAllEvents(app) + if err != nil { + return err + } else { + return nil + } +} + // UpdateModulesForCourse updates all modules for a course // Does Updates for ws and ss semester sequentially // Update runs through the following steps: @@ -90,11 +100,6 @@ func UpdateModulesForCourse(app *pocketbase.PocketBase, course string) error { seminarGroups := fetch.GetSeminarGroupsEventsFromHTML(courses) - collection, dbError := db.FindCollection(app, "events") - if dbError != nil { - return apis.NewNotFoundError("Collection not found", dbError) - } - seminarGroups = fetch.ClearEmptySeminarGroups(seminarGroups) seminarGroups = fetch.ReplaceEmptyEventNames(seminarGroups) @@ -120,7 +125,7 @@ func UpdateModulesForCourse(app *pocketbase.PocketBase, course string) error { //if there are no events in the database, save the new events if len(events) == 0 { - _, dbError = db.SaveEvents(seminarGroups, collection, app) + _, dbError := db.SaveEvents(seminarGroups, app) if dbError != nil { return apis.NewNotFoundError("Events could not be saved", dbError) } @@ -146,7 +151,7 @@ func UpdateModulesForCourse(app *pocketbase.PocketBase, course string) error { } //save the new events - _, dbError = db.SaveEvents(seminarGroups, collection, app) + _, dbError := db.SaveEvents(seminarGroups, app) if dbError != nil { return apis.NewNotFoundError("Events could not be saved", dbError) } diff --git a/backend/service/fetch/fetchSeminarEventService.go b/backend/service/fetch/fetchSeminarEventService.go index 24e6baa..183b1aa 100644 --- a/backend/service/fetch/fetchSeminarEventService.go +++ b/backend/service/fetch/fetchSeminarEventService.go @@ -2,6 +2,7 @@ package fetch import ( "fmt" + "github.com/google/uuid" "github.com/labstack/echo/v5" "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/apis" @@ -23,19 +24,14 @@ func GetSeminarEvents(c echo.Context, app *pocketbase.PocketBase) error { seminarGroups := GetSeminarGroupsEventsFromHTML(seminarGroupsLabel) - collection, dbError := db.FindCollection(app, "events") - if dbError != nil { - return apis.NewNotFoundError("Collection not found", dbError) - } - seminarGroups = ClearEmptySeminarGroups(seminarGroups) seminarGroups = ReplaceEmptyEventNames(seminarGroups) - savedRecords, dbError := db.SaveEvents(seminarGroups, collection, app) + savedRecords, dbError := db.SaveEvents(seminarGroups, app) if dbError != nil { - return apis.NewNotFoundError("Events could not be saved", dbError) + return apis.NewNotFoundError("Events could not be saved", dbError.Error()) } return c.JSON(http.StatusOK, savedRecords) @@ -100,16 +96,28 @@ func parseSeminarGroup(result string) model.SeminarGroup { splitEventsByWeekVal := splitEventsByWeek(eventsWithCombinedWeeks) events := splitEventsBySingleWeek(splitEventsByWeekVal) semesterString := findFirstSpanWithClass(table, "header-0-2-0").FirstChild.Data + course := findFirstSpanWithClass(table, "header-2-0-1").FirstChild.Data semester, year := extractSemesterAndYear(semesterString) events = convertWeeksToDates(events, semester, year) + events = generateUUIDs(events, course) var seminarGroup = model.SeminarGroup{ University: findFirstSpanWithClass(table, "header-1-0-0").FirstChild.Data, - Course: findFirstSpanWithClass(table, "header-2-0-1").FirstChild.Data, + Course: course, Events: events, } return seminarGroup } +func generateUUIDs(events []model.Event, course string) []model.Event { + for i, event := range events { + // generate a hash value from the event name, course and semester + hash := uuid.NewSHA1(uuid.NameSpaceOID, []byte(event.Name+course)) + events[i].UUID = hash.String() + } + return events + +} + func convertWeeksToDates(events []model.Event, semester string, year string) []model.Event { var newEvents []model.Event eventYear, _ := strconv.Atoi(year) diff --git a/backend/service/fetch/fetchSeminarEventService_test.go b/backend/service/fetch/fetchSeminarEventService_test.go index 3284402..111f0b8 100644 --- a/backend/service/fetch/fetchSeminarEventService_test.go +++ b/backend/service/fetch/fetchSeminarEventService_test.go @@ -118,3 +118,57 @@ func Test_replaceEmptyEventNames(t *testing.T) { }) } } + +func Test_generateUUIDs(t *testing.T) { + type args struct { + events []model.Event + course string + } + tests := []struct { + name string + args args + want []model.Event + }{ + { + name: "Test 1", + args: args{ + events: []model.Event{ + { + Name: " Arbeitssicherheit / Rechtsformen von Unternehmen B435 SBB (wpf) & B348 BIB (pf) 5. FS", + }, + }, + course: "21BIB-2a", + }, + want: []model.Event{ + { + Name: " Arbeitssicherheit / Rechtsformen von Unternehmen B435 SBB (wpf) & B348 BIB (pf) 5. FS", + UUID: "3720afdc-10c7-5b72-9489-cffb70cb0c13", + }, + }, + }, + { + name: "Test 2", + args: args{ + events: []model.Event{ + { + Name: " Arbeitssicherheit / Rechtsformen von Unternehmen B435 SBB (wpf) & B348 BIB (pf) 5. FS", + }, + }, + course: "21BIB-2b", + }, + want: []model.Event{ + { + Name: " Arbeitssicherheit / Rechtsformen von Unternehmen B435 SBB (wpf) & B348 BIB (pf) 5. FS", + UUID: "81083480-bcf1-5452-af84-bb27d79282d8", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := generateUUIDs(tt.args.events, tt.args.course); !reflect.DeepEqual(got, tt.want) { + t.Errorf("generateUUIDs() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/backend/service/ical/ical.go b/backend/service/ical/ical.go index a0ad8d4..baee837 100644 --- a/backend/service/ical/ical.go +++ b/backend/service/ical/ical.go @@ -16,8 +16,6 @@ import ( const expirationTime = 5 * time.Minute func Feed(c echo.Context, app *pocketbase.PocketBase, token string) error { - layout := "2006-01-02 15:04:05 -0700 MST" - var result string var responseWriter = c.Response().Writer feed, err := db.FindFeedByToken(token, app) @@ -25,17 +23,14 @@ func Feed(c echo.Context, app *pocketbase.PocketBase, token string) error { return c.JSON(http.StatusNotFound, err) } - created, _ := time.Parse(layout, feed.Created) - var modules []model.FeedCollection _ = json.Unmarshal([]byte(feed.Modules), &modules) - if created.Add(time.Hour * 265).Before(time.Now()) { - newFeed, err := createFeedForToken(app, modules) - if err != nil { - return c.JSON(http.StatusInternalServerError, err) - } - result = newFeed.Content + + newFeed, err := createFeedForToken(app, modules) + if err != nil { + return c.JSON(http.StatusInternalServerError, err) } + result = newFeed.Content responseWriter.Header().Set("Content-type", "text/calendar") responseWriter.Header().Set("charset", "utf-8") diff --git a/backend/service/ical/icalFileGeneration.go b/backend/service/ical/icalFileGeneration.go index 14d64ba..2b77c3a 100644 --- a/backend/service/ical/icalFileGeneration.go +++ b/backend/service/ical/icalFileGeneration.go @@ -50,7 +50,7 @@ func replaceNameIfUserDefined(name string, mapping []model.FeedCollection) strin return name } -func generateDescription(event *model.Event) string { +func generateDescription(event model.Event) string { var description string if !functions.OnlyWhitespace(event.Notes) { diff --git a/backend/service/ical/icalJsonMigrate.go b/backend/service/ical/icalJsonMigrate.go new file mode 100644 index 0000000..94ac33d --- /dev/null +++ b/backend/service/ical/icalJsonMigrate.go @@ -0,0 +1,58 @@ +package ical + +import ( + "encoding/json" + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase" + "htwkalender/model" +) + +//update ical feed json +//add uuid field +//remove module name field + +func MigrateFeedJson(app *pocketbase.PocketBase) error { + + records, err := app.Dao().FindRecordsByFilter("feeds", "1=1", "-created", 0, 0) + if err != nil { + return err + } + + for _, feed := range records { + + var modules []model.FeedCollection + + err := json.Unmarshal([]byte(feed.GetString("modules")), &modules) + if err != nil { + return err + } + + var uuidFeedCollections []model.FeedCollection + + for _, module := range modules { + uuid := searchUUIDForModule(app, module) + + if uuid != "" { + uuidFeedCollections = append(uuidFeedCollections, model.FeedCollection{UUID: uuid, Name: module.Name, Course: module.Course, UserDefinedName: module.UserDefinedName}) + } + } + + jsonModules, _ := json.Marshal(uuidFeedCollections) + feed.Set("modules", string(jsonModules)) + + err = app.Dao().SaveRecord(feed) + if err != nil { + return err + } + } + return nil +} + +func searchUUIDForModule(app *pocketbase.PocketBase, module model.FeedCollection) string { + var event model.Event + err := app.Dao().DB().Select("*").From("events").Where(dbx.NewExp("Name = {:name} AND course = {:course}", dbx.Params{"name": module.Name, "course": module.Course})).One(&event) + if err != nil { + return "" + } + return event.UUID +} diff --git a/frontend/src/api/fetchCourse.ts b/frontend/src/api/fetchCourse.ts index 3f23516..b641635 100644 --- a/frontend/src/api/fetchCourse.ts +++ b/frontend/src/api/fetchCourse.ts @@ -27,6 +27,7 @@ export async function fetchModulesByCourseAndSemester( modulesResponse.forEach((module: Module) => modules.push( new Module( + module.uuid, module.name, course, module.name, @@ -50,6 +51,7 @@ export async function fetchAllModules(): Promise { responseModules.forEach((module: Module) => { modules.push( new Module( + module.uuid, module.name, module.course, module.name, diff --git a/frontend/src/api/fetchModule.ts b/frontend/src/api/fetchModule.ts index 17a7ec9..e6a7f1c 100644 --- a/frontend/src/api/fetchModule.ts +++ b/frontend/src/api/fetchModule.ts @@ -1,12 +1,12 @@ import { Module } from "../model/module"; -export async function fetchModule(name: string): Promise { +export async function fetchModule(module: Module): Promise { const request = new Request("/api/module", { - method: "GET", + method: "POST", headers: { "Content-Type": "application/json", - Name: encodeURI(name), }, + body: JSON.stringify(module), }); return await fetch(request) @@ -16,6 +16,7 @@ export async function fetchModule(name: string): Promise { .then( (module: Module) => new Module( + module.uuid, module.name, module.course, module.name, diff --git a/frontend/src/components/AdditionalModules.vue b/frontend/src/components/AdditionalModules.vue index 7074611..868fdf4 100644 --- a/frontend/src/components/AdditionalModules.vue +++ b/frontend/src/components/AdditionalModules.vue @@ -38,10 +38,9 @@ const ModuleInformation = defineAsyncComponent( () => import("./ModuleInformation.vue"), ); -async function showInfo(moduleName: string) { - const module: Ref = ref(new Module("", "", "", "", "", [])); - await fetchModule(moduleName).then((data) => { - module.value = data; +async function showInfo(module: Module) { + await fetchModule(module).then((data) => { + module = data; }); dialog.open(ModuleInformation, { props: { @@ -66,7 +65,7 @@ const selectAll = ref(false); const onSelectAllChange = (event: MultiSelectAllChangeEvent) => { selectedModules.value = event.checked - ? modules.value.map((module) => module) + ? modules.value.map((module: Module) => module) : []; selectAll.value = event.checked; }; @@ -112,7 +111,7 @@ function selectChange() { rounded outlined aria-label="Information" - @click.stop="showInfo(slotProps.option.name)" + @click.stop="showInfo(slotProps.option)" > diff --git a/frontend/src/components/editCalendar/EditAdditionalModules.vue b/frontend/src/components/editCalendar/EditAdditionalModules.vue index 9f696e8..5b07d39 100644 --- a/frontend/src/components/editCalendar/EditAdditionalModules.vue +++ b/frontend/src/components/editCalendar/EditAdditionalModules.vue @@ -36,9 +36,8 @@ const ModuleInformation = defineAsyncComponent( () => import("../ModuleInformation.vue"), ); -async function showInfo(moduleName: string) { - const module: Ref = ref(new Module("", "", "", "", "", [])); - await fetchModule(moduleName).then((data) => { +async function showInfo(module: Module) { + await fetchModule(module).then((data) => { module.value = data; }); dialog.open(ModuleInformation, { @@ -110,7 +109,7 @@ function selectChange() { rounded outlined aria-label="Information" - @click.stop="showInfo(slotProps.option.name)" + @click.stop="showInfo(slotProps.option)" > diff --git a/frontend/src/model/module.ts b/frontend/src/model/module.ts index 8be7e35..9633c9d 100644 --- a/frontend/src/model/module.ts +++ b/frontend/src/model/module.ts @@ -2,6 +2,7 @@ import { Event } from "./event"; export class Module { constructor( + public uuid: string, public name: string, public course: string, public userDefinedName: string,