mirror of
https://github.com/Unkn0wnCat/matrix-veles.git
synced 2025-04-28 09:46:51 +02:00
api: Add graphql endpoint
This commit is contained in:
parent
9e05c54d81
commit
8256b70fcb
21 changed files with 9111 additions and 15 deletions
15
.graphqlconfig
Normal file
15
.graphqlconfig
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "Main Schema",
|
||||
"schemaPath": "graph/schema.graphqls",
|
||||
"extensions": {
|
||||
"endpoints": {
|
||||
"Default GraphQL Endpoint": {
|
||||
"url": "http://localhost:8123/api/query",
|
||||
"headers": {
|
||||
"user-agent": "JS GraphQL"
|
||||
},
|
||||
"introspect": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
4
go.mod
4
go.mod
|
@ -4,13 +4,15 @@ go 1.16
|
|||
|
||||
require (
|
||||
github.com/766b/chi-prometheus v0.0.0-20211217152057-87afa9aa2ca8
|
||||
github.com/99designs/gqlgen v0.17.1
|
||||
github.com/go-chi/chi v1.5.4 // indirect
|
||||
github.com/go-chi/chi/v5 v5.0.7
|
||||
github.com/go-chi/cors v1.2.0 // indirect
|
||||
github.com/go-chi/cors v1.2.0
|
||||
github.com/golang-jwt/jwt/v4 v4.3.0
|
||||
github.com/prometheus/client_golang v1.12.1
|
||||
github.com/spf13/cobra v1.3.0
|
||||
github.com/spf13/viper v1.10.1
|
||||
github.com/vektah/gqlparser/v2 v2.4.0
|
||||
go.mongodb.org/mongo-driver v1.8.3
|
||||
go.opentelemetry.io/otel v1.4.1
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.4.1
|
||||
|
|
39
go.sum
39
go.sum
|
@ -48,17 +48,26 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
|
|||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/766b/chi-prometheus v0.0.0-20211217152057-87afa9aa2ca8 h1:hK1G69lDhhrGqJbRA5i1rmT2KI/W77MSdr7hEGHqWdQ=
|
||||
github.com/766b/chi-prometheus v0.0.0-20211217152057-87afa9aa2ca8/go.mod h1:X/LhbmoBoRu8TxoGIOIraVNhfz3hhikJoaelrOuhdPY=
|
||||
github.com/99designs/gqlgen v0.17.1 h1:i2qQMPKHQjHgBWYIpO4TsaQpPqMHCPK1+h95ipvH8VU=
|
||||
github.com/99designs/gqlgen v0.17.1/go.mod h1:K5fzLKwtph+FFgh9j7nFbRUdBKvTcGnsta51fsMTn3o=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||
github.com/agnivade/levenshtein v1.1.0 h1:n6qGwyHG61v3ABce1rPVZklEYRT8NFpCMrpZdBUbYGM=
|
||||
github.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
|
||||
|
@ -104,11 +113,15 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH
|
|||
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g=
|
||||
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
|
@ -230,6 +243,7 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
|
|||
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
||||
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
|
||||
|
@ -254,6 +268,7 @@ github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
|
|||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
|
@ -282,6 +297,7 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
|
|||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
|
@ -298,9 +314,12 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc=
|
||||
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
|
||||
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/matryer/moq v0.2.3 h1:Q06vEqnBYjjfx5KKgHfYRKE/lvlRu+Nj+xodG4YdHnU=
|
||||
github.com/matryer/moq v0.2.3/go.mod h1:9RtPYjTnH1bSBIkpvtHkFN7nbWAnO7oRpdJkEIn6UtE=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
|
@ -323,6 +342,7 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
|
|||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.2.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
|
||||
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
@ -376,11 +396,16 @@ github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0
|
|||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
|
||||
github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
|
@ -418,6 +443,10 @@ github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
|
|||
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/sjson v1.1.5/go.mod h1:VuJzsZnTowhSxWdOgsAnb886i4AjEyTkk7tNtsL7EYE=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/vektah/gqlparser/v2 v2.4.0 h1:EmA4dw9mqHm0j6Xzb9T21hOrp3oXmxnS40vwki70DZU=
|
||||
github.com/vektah/gqlparser/v2 v2.4.0/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
|
||||
|
@ -431,6 +460,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
|||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs=
|
||||
|
@ -506,6 +536,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -549,8 +581,9 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
|
|||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c=
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -650,6 +683,7 @@ golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
@ -713,6 +747,7 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY
|
|||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200815165600-90abf76919f3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
|
@ -726,6 +761,8 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8=
|
||||
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
57
gqlgen.yml
Normal file
57
gqlgen.yml
Normal file
|
@ -0,0 +1,57 @@
|
|||
# Where are all the schema files located? globs are supported eg src/**/*.graphqls
|
||||
schema:
|
||||
- graph/*.graphqls
|
||||
|
||||
# Where should the generated server code go?
|
||||
exec:
|
||||
filename: graph/generated/generated.go
|
||||
package: generated
|
||||
|
||||
# Uncomment to enable federation
|
||||
# federation:
|
||||
# filename: graph/generated/federation.go
|
||||
# package: generated
|
||||
|
||||
# Where should any generated models go?
|
||||
model:
|
||||
filename: graph/model/models_gen.go
|
||||
package: model
|
||||
|
||||
# Where should the resolver implementations go?
|
||||
resolver:
|
||||
layout: follow-schema
|
||||
dir: graph
|
||||
package: graph
|
||||
|
||||
# Optional: turn on use ` + "`" + `gqlgen:"fieldName"` + "`" + ` tags in your models
|
||||
# struct_tag: json
|
||||
|
||||
# Optional: turn on to use []Thing instead of []*Thing
|
||||
# omit_slice_element_pointers: false
|
||||
|
||||
# Optional: set to speed up generation time by not performing a final validation pass.
|
||||
# skip_validation: true
|
||||
|
||||
# gqlgen will search for any type names in the schema in these go packages
|
||||
# if they match it will use them, otherwise it will generate them.
|
||||
autobind:
|
||||
- "github.com/Unkn0wnCat/matrix-veles/internal/db/model"
|
||||
- "github.com/Unkn0wnCat/matrix-veles/graph/model"
|
||||
|
||||
# This section declares type mapping between the GraphQL and go type systems
|
||||
#
|
||||
# The first line in each type will be used as defaults for resolver arguments and
|
||||
# modelgen, the others will be allowed when binding to fields. Configure them to
|
||||
# your liking
|
||||
models:
|
||||
ID:
|
||||
model:
|
||||
- github.com/99designs/gqlgen/graphql.ID
|
||||
- github.com/99designs/gqlgen/graphql.Int
|
||||
- github.com/99designs/gqlgen/graphql.Int64
|
||||
- github.com/99designs/gqlgen/graphql.Int32
|
||||
Int:
|
||||
model:
|
||||
- github.com/99designs/gqlgen/graphql.Int
|
||||
- github.com/99designs/gqlgen/graphql.Int64
|
||||
- github.com/99designs/gqlgen/graphql.Int32
|
42
graph/examples/examples.graphql
Normal file
42
graph/examples/examples.graphql
Normal file
|
@ -0,0 +1,42 @@
|
|||
query {
|
||||
entries(first:2) {
|
||||
pageInfo {
|
||||
hasPreviousPage
|
||||
hasNextPage
|
||||
startCursor
|
||||
endCursor
|
||||
}
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
tags
|
||||
timestamp
|
||||
comments {
|
||||
edges {
|
||||
node {
|
||||
author {
|
||||
id
|
||||
}
|
||||
content
|
||||
timestamp
|
||||
}
|
||||
}
|
||||
}
|
||||
partOf {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
maintainers {
|
||||
edges {
|
||||
node {
|
||||
username
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7217
graph/generated/generated.go
Normal file
7217
graph/generated/generated.go
Normal file
File diff suppressed because it is too large
Load diff
454
graph/helpers.go
Normal file
454
graph/helpers.go
Normal file
|
@ -0,0 +1,454 @@
|
|||
package graph
|
||||
|
||||
import (
|
||||
"github.com/Unkn0wnCat/matrix-veles/graph/model"
|
||||
model2 "github.com/Unkn0wnCat/matrix-veles/internal/db/model"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
func buildStringFilter(filter *model.StringFilter) bson.M {
|
||||
compiledFilter := bson.M{}
|
||||
|
||||
if filter != nil {
|
||||
if filter.Eq != nil {
|
||||
compiledFilter["$eq"] = *filter.Eq
|
||||
}
|
||||
if filter.Neq != nil {
|
||||
compiledFilter["$ne"] = *filter.Eq
|
||||
}
|
||||
if filter.Regex != nil {
|
||||
compiledFilter["$regex"] = *filter.Regex
|
||||
}
|
||||
}
|
||||
|
||||
return compiledFilter
|
||||
}
|
||||
|
||||
func buildTimestampFilter(filter *model.TimestampFilter) (*bson.M, error) {
|
||||
compiledFilter := bson.M{}
|
||||
|
||||
if filter != nil {
|
||||
if filter.After != nil {
|
||||
compiledFilter["$gt"] = *filter.After
|
||||
}
|
||||
if filter.Before != nil {
|
||||
compiledFilter["$lt"] = *filter.Before
|
||||
}
|
||||
}
|
||||
|
||||
return &compiledFilter, nil
|
||||
}
|
||||
|
||||
func buildIntFilter(filter *model.IntFilter) bson.M {
|
||||
compiledFilter := bson.M{}
|
||||
|
||||
if filter != nil {
|
||||
if filter.Eq != nil {
|
||||
compiledFilter["$eq"] = *filter.Eq
|
||||
}
|
||||
if filter.Neq != nil {
|
||||
compiledFilter["$ne"] = *filter.Neq
|
||||
}
|
||||
if filter.Gt != nil {
|
||||
compiledFilter["$gt"] = *filter.Gt
|
||||
}
|
||||
if filter.Lt != nil {
|
||||
compiledFilter["$lt"] = *filter.Lt
|
||||
}
|
||||
}
|
||||
|
||||
return compiledFilter
|
||||
}
|
||||
|
||||
func buildStringArrayFilter(filter *model.StringArrayFilter) bson.M {
|
||||
compiledFilter := bson.M{}
|
||||
|
||||
if filter != nil {
|
||||
if filter.ElemMatch != nil {
|
||||
compiledFilter["$elemMatch"] = buildStringFilter(filter.ElemMatch)
|
||||
}
|
||||
if filter.ContainsAll != nil {
|
||||
compiledFilter["$all"] = filter.ContainsAll
|
||||
}
|
||||
if filter.Length != nil {
|
||||
compiledFilter["$size"] = *filter.Length
|
||||
}
|
||||
}
|
||||
|
||||
return compiledFilter
|
||||
}
|
||||
|
||||
func idArrayToPrimitiveID(ids []*string) ([]primitive.ObjectID, error) {
|
||||
var pIds []primitive.ObjectID
|
||||
|
||||
for _, id := range ids {
|
||||
pId, err := primitive.ObjectIDFromHex(*id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pIds = append(pIds, pId)
|
||||
}
|
||||
|
||||
return pIds, nil
|
||||
}
|
||||
|
||||
func buildIDArrayFilter(filter *model.IDArrayFilter) (bson.M, error) {
|
||||
compiledFilter := bson.M{}
|
||||
var err error
|
||||
|
||||
if filter != nil {
|
||||
if filter.ContainsAll != nil {
|
||||
compiledFilter["$all"], err = idArrayToPrimitiveID(filter.ContainsAll)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if filter.Length != nil {
|
||||
compiledFilter["$size"] = *filter.Length
|
||||
}
|
||||
}
|
||||
|
||||
return compiledFilter, nil
|
||||
}
|
||||
|
||||
func buildSortRule(sort *model.SortRule) interface{} {
|
||||
if sort.Direction == "ASC" {
|
||||
return 1
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
func buildDBUserFilter(first *int, after *string, filter *model.UserFilter, sort *model.UserSort) (*bson.M, *bson.M, *int64, error) {
|
||||
compiledFilter := bson.M{}
|
||||
compiledSort := bson.M{}
|
||||
|
||||
var filterBson *bson.M
|
||||
var cursorBson *bson.M
|
||||
limit := 25
|
||||
|
||||
if sort != nil {
|
||||
if sort.ID != nil {
|
||||
compiledSort["_id"] = buildSortRule(sort.ID)
|
||||
}
|
||||
if sort.Username != nil {
|
||||
compiledSort["username"] = buildSortRule(sort.Username)
|
||||
}
|
||||
if sort.Admin != nil {
|
||||
compiledSort["admin"] = buildSortRule(sort.Admin)
|
||||
}
|
||||
}
|
||||
|
||||
if first != nil {
|
||||
limit = *first
|
||||
}
|
||||
|
||||
if after != nil {
|
||||
cursorBsonW := bson.M{}
|
||||
|
||||
afterID, err := primitive.ObjectIDFromHex(*after)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
cursorBsonW["_id"] = bson.M{"$gt": afterID}
|
||||
|
||||
cursorBson = &cursorBsonW
|
||||
}
|
||||
|
||||
if filter != nil {
|
||||
filterBsonW := bson.M{}
|
||||
|
||||
if filter.ID != nil {
|
||||
filterBsonW["_id"] = *filter.ID
|
||||
}
|
||||
|
||||
if filter.Username != nil {
|
||||
filterBsonW["username"] = buildStringFilter(filter.Username)
|
||||
}
|
||||
|
||||
if filter.Admin != nil {
|
||||
filterBsonW["admin"] = *filter.Admin
|
||||
}
|
||||
|
||||
if filter.MatrixLinks != nil {
|
||||
filterBsonW["matrix_links"] = buildStringArrayFilter(filter.MatrixLinks)
|
||||
}
|
||||
|
||||
if filter.PendingMatrixLinks != nil {
|
||||
filterBsonW["pending_matrix_links"] = buildStringArrayFilter(filter.PendingMatrixLinks)
|
||||
}
|
||||
|
||||
filterBson = &filterBsonW
|
||||
}
|
||||
|
||||
if filterBson != nil && cursorBson != nil {
|
||||
compiledFilter["$and"] = bson.A{*cursorBson, *filterBson}
|
||||
}
|
||||
|
||||
if filterBson == nil && cursorBson != nil {
|
||||
compiledFilter = *cursorBson
|
||||
}
|
||||
|
||||
if filterBson != nil && cursorBson == nil {
|
||||
compiledFilter = *filterBson
|
||||
}
|
||||
|
||||
convLimit := int64(limit)
|
||||
|
||||
return &compiledFilter, &compiledSort, &convLimit, nil
|
||||
}
|
||||
|
||||
func buildDBListFilter(first *int, after *string, filter *model.ListFilter, sort *model.ListSort) (*bson.M, *bson.M, *int64, error) {
|
||||
compiledFilter := bson.M{}
|
||||
compiledSort := bson.M{}
|
||||
|
||||
var filterBson *bson.M
|
||||
var cursorBson *bson.M
|
||||
limit := 25
|
||||
|
||||
var err error
|
||||
|
||||
if sort != nil {
|
||||
if sort.ID != nil {
|
||||
compiledSort["_id"] = buildSortRule(sort.ID)
|
||||
}
|
||||
if sort.Name != nil {
|
||||
compiledSort["name"] = buildSortRule(sort.Name)
|
||||
}
|
||||
}
|
||||
|
||||
if first != nil {
|
||||
limit = *first
|
||||
}
|
||||
|
||||
if after != nil {
|
||||
cursorBsonW := bson.M{}
|
||||
|
||||
afterID, err := primitive.ObjectIDFromHex(*after)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
cursorBsonW["_id"] = bson.M{"$gt": afterID}
|
||||
|
||||
cursorBson = &cursorBsonW
|
||||
}
|
||||
|
||||
if filter != nil {
|
||||
filterBsonW := bson.M{}
|
||||
|
||||
if filter.ID != nil {
|
||||
filterBsonW["_id"] = *filter.ID
|
||||
}
|
||||
|
||||
if filter.Name != nil {
|
||||
filterBsonW["name"] = buildStringFilter(filter.Name)
|
||||
}
|
||||
|
||||
if filter.Tags != nil {
|
||||
filterBsonW["tags"] = buildStringArrayFilter(filter.Tags)
|
||||
}
|
||||
|
||||
if filter.Maintainers != nil {
|
||||
filterBsonW["maintainers"], err = buildIDArrayFilter(filter.Maintainers)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
filterBson = &filterBsonW
|
||||
}
|
||||
|
||||
if filterBson != nil && cursorBson != nil {
|
||||
compiledFilter["$and"] = bson.A{*cursorBson, *filterBson}
|
||||
}
|
||||
|
||||
if filterBson == nil && cursorBson != nil {
|
||||
compiledFilter = *cursorBson
|
||||
}
|
||||
|
||||
if filterBson != nil && cursorBson == nil {
|
||||
compiledFilter = *filterBson
|
||||
}
|
||||
|
||||
convLimit := int64(limit)
|
||||
|
||||
return &compiledFilter, &compiledSort, &convLimit, nil
|
||||
}
|
||||
|
||||
func buildDBEntryFilter(first *int, after *string, filter *model.EntryFilter, sort *model.EntrySort) (*bson.M, *bson.M, *int64, error) {
|
||||
compiledFilter := bson.M{}
|
||||
compiledSort := bson.M{}
|
||||
|
||||
var filterBson *bson.M
|
||||
var cursorBson *bson.M
|
||||
limit := 25
|
||||
|
||||
var err error
|
||||
|
||||
if sort != nil {
|
||||
if sort.ID != nil {
|
||||
compiledSort["_id"] = buildSortRule(sort.ID)
|
||||
}
|
||||
if sort.Timestamp != nil {
|
||||
compiledSort["timestamp"] = buildSortRule(sort.Timestamp)
|
||||
}
|
||||
if sort.AddedBy != nil {
|
||||
compiledSort["added_by"] = buildSortRule(sort.AddedBy)
|
||||
}
|
||||
if sort.HashValue != nil {
|
||||
compiledSort["hash_value"] = buildSortRule(sort.HashValue)
|
||||
}
|
||||
}
|
||||
|
||||
if first != nil {
|
||||
limit = *first
|
||||
}
|
||||
|
||||
if after != nil {
|
||||
cursorBsonW := bson.M{}
|
||||
|
||||
afterID, err := primitive.ObjectIDFromHex(*after)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
cursorBsonW["_id"] = bson.M{"$gt": afterID}
|
||||
|
||||
cursorBson = &cursorBsonW
|
||||
}
|
||||
|
||||
if filter != nil {
|
||||
filterBsonW := bson.M{}
|
||||
|
||||
if filter.ID != nil {
|
||||
filterBsonW["_id"] = *filter.ID
|
||||
}
|
||||
|
||||
if filter.HashValue != nil {
|
||||
filterBsonW["hash_value"] = buildStringFilter(filter.HashValue)
|
||||
}
|
||||
|
||||
if filter.Tags != nil {
|
||||
filterBsonW["tags"] = buildStringArrayFilter(filter.Tags)
|
||||
}
|
||||
|
||||
if filter.AddedBy != nil {
|
||||
dbId, err := primitive.ObjectIDFromHex(*filter.AddedBy)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
filterBsonW["added_by"] = dbId
|
||||
}
|
||||
|
||||
if filter.Timestamp != nil {
|
||||
filterBsonW["timestamp"], err = buildTimestampFilter(filter.Timestamp)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if filter.FileURL != nil {
|
||||
filterBsonW["file_url"] = buildStringFilter(filter.FileURL)
|
||||
}
|
||||
|
||||
if filter.PartOf != nil {
|
||||
filterBsonW["part_of"], err = buildIDArrayFilter(filter.PartOf)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
filterBson = &filterBsonW
|
||||
}
|
||||
|
||||
if filterBson != nil && cursorBson != nil {
|
||||
compiledFilter["$and"] = bson.A{*cursorBson, *filterBson}
|
||||
}
|
||||
|
||||
if filterBson == nil && cursorBson != nil {
|
||||
compiledFilter = *cursorBson
|
||||
}
|
||||
|
||||
if filterBson != nil && cursorBson == nil {
|
||||
compiledFilter = *filterBson
|
||||
}
|
||||
|
||||
convLimit := int64(limit)
|
||||
|
||||
return &compiledFilter, &compiledSort, &convLimit, nil
|
||||
}
|
||||
|
||||
func ResolveComments(comments []*model2.DBComment, first *int, after *string) (*model.CommentConnection, error) {
|
||||
if len(comments) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
startIndex := 0
|
||||
|
||||
if after != nil {
|
||||
afterTs, err := time.Parse(time.RFC3339Nano, *after)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
set := false
|
||||
|
||||
for i, comment := range comments {
|
||||
if afterTs.Before(comment.Timestamp) {
|
||||
startIndex = i
|
||||
set = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !set {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
if startIndex >= len(comments) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
comments = comments[startIndex:]
|
||||
|
||||
length := 25
|
||||
|
||||
if first != nil {
|
||||
length = *first
|
||||
}
|
||||
|
||||
cut := false
|
||||
|
||||
if len(comments) > length {
|
||||
cut = true
|
||||
comments = comments[:length]
|
||||
}
|
||||
|
||||
var edges []*model.CommentEdge
|
||||
|
||||
for _, comment := range comments {
|
||||
edges = append(edges, &model.CommentEdge{
|
||||
Node: model.MakeComment(comment),
|
||||
Cursor: comment.Timestamp.Format(time.RFC3339Nano),
|
||||
})
|
||||
}
|
||||
log.Println(edges)
|
||||
|
||||
return &model.CommentConnection{
|
||||
PageInfo: &model.PageInfo{
|
||||
HasPreviousPage: startIndex > 0,
|
||||
HasNextPage: cut,
|
||||
StartCursor: edges[0].Cursor,
|
||||
EndCursor: edges[len(edges)-1].Cursor,
|
||||
},
|
||||
Edges: nil,
|
||||
}, nil
|
||||
}
|
21
graph/model/comment.go
Normal file
21
graph/model/comment.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"github.com/Unkn0wnCat/matrix-veles/internal/db/model"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Comment struct {
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
AuthorID *primitive.ObjectID
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
func MakeComment(dbComment *model.DBComment) *Comment {
|
||||
return &Comment{
|
||||
Timestamp: dbComment.Timestamp,
|
||||
AuthorID: dbComment.CommentedBy,
|
||||
Content: dbComment.Content,
|
||||
}
|
||||
}
|
31
graph/model/entry.go
Normal file
31
graph/model/entry.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"github.com/Unkn0wnCat/matrix-veles/internal/db/model"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Entry struct {
|
||||
ID string `json:"id"`
|
||||
Tags []string `json:"tags"`
|
||||
PartOfIDs []*primitive.ObjectID
|
||||
HashValue string `json:"hashValue"`
|
||||
FileURL *string `json:"fileUrl"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
AddedByID primitive.ObjectID
|
||||
RawComments []*model.DBComment
|
||||
}
|
||||
|
||||
func MakeEntry(dbEntry *model.DBEntry) *Entry {
|
||||
return &Entry{
|
||||
ID: dbEntry.ID.Hex(),
|
||||
Tags: dbEntry.Tags,
|
||||
PartOfIDs: dbEntry.PartOf,
|
||||
HashValue: dbEntry.HashValue,
|
||||
FileURL: &dbEntry.FileURL,
|
||||
Timestamp: dbEntry.Timestamp,
|
||||
AddedByID: *dbEntry.AddedBy,
|
||||
RawComments: dbEntry.Comments,
|
||||
}
|
||||
}
|
24
graph/model/list.go
Normal file
24
graph/model/list.go
Normal file
|
@ -0,0 +1,24 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"github.com/Unkn0wnCat/matrix-veles/internal/db/model"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
type List struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Tags []string `json:"tags"`
|
||||
RawComments []*model.DBComment
|
||||
MaintainerIDs []*primitive.ObjectID
|
||||
}
|
||||
|
||||
func MakeList(dbList *model.DBHashList) *List {
|
||||
return &List{
|
||||
ID: dbList.ID.Hex(),
|
||||
Name: dbList.Name,
|
||||
Tags: dbList.Tags,
|
||||
RawComments: dbList.Comments,
|
||||
MaintainerIDs: dbList.Maintainers,
|
||||
}
|
||||
}
|
197
graph/model/models_gen.go
Normal file
197
graph/model/models_gen.go
Normal file
|
@ -0,0 +1,197 @@
|
|||
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CommentConnection struct {
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
Edges []*CommentEdge `json:"edges"`
|
||||
}
|
||||
|
||||
type CommentEdge struct {
|
||||
Node *Comment `json:"node"`
|
||||
Cursor string `json:"cursor"`
|
||||
}
|
||||
|
||||
type EntryArrayFilter struct {
|
||||
ContainsAll []*EntryFilter `json:"containsAll"`
|
||||
ContainsOne []*EntryFilter `json:"containsOne"`
|
||||
Length *int `json:"length"`
|
||||
}
|
||||
|
||||
type EntryConnection struct {
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
Edges []*EntryEdge `json:"edges"`
|
||||
}
|
||||
|
||||
type EntryEdge struct {
|
||||
Node *Entry `json:"node"`
|
||||
Cursor string `json:"cursor"`
|
||||
}
|
||||
|
||||
type EntryFilter struct {
|
||||
ID *string `json:"id"`
|
||||
HashValue *StringFilter `json:"hashValue"`
|
||||
Tags *StringArrayFilter `json:"tags"`
|
||||
AddedBy *string `json:"addedBy"`
|
||||
FileURL *StringFilter `json:"fileUrl"`
|
||||
Timestamp *TimestampFilter `json:"timestamp"`
|
||||
PartOf *IDArrayFilter `json:"partOf"`
|
||||
}
|
||||
|
||||
type EntrySort struct {
|
||||
ID *SortRule `json:"id"`
|
||||
HashValue *SortRule `json:"hashValue"`
|
||||
Timestamp *SortRule `json:"timestamp"`
|
||||
AddedBy *SortRule `json:"addedBy"`
|
||||
}
|
||||
|
||||
type IDArrayFilter struct {
|
||||
ContainsAll []*string `json:"containsAll"`
|
||||
Length *int `json:"length"`
|
||||
}
|
||||
|
||||
type IntFilter struct {
|
||||
Gt *int `json:"gt"`
|
||||
Lt *int `json:"lt"`
|
||||
Eq *int `json:"eq"`
|
||||
Neq *int `json:"neq"`
|
||||
}
|
||||
|
||||
type ListArrayFilter struct {
|
||||
ContainsAll []*ListFilter `json:"containsAll"`
|
||||
ContainsOne []*ListFilter `json:"containsOne"`
|
||||
Length *int `json:"length"`
|
||||
}
|
||||
|
||||
type ListConnection struct {
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
Edges []*ListEdge `json:"edges"`
|
||||
}
|
||||
|
||||
type ListEdge struct {
|
||||
Node *List `json:"node"`
|
||||
Cursor string `json:"cursor"`
|
||||
}
|
||||
|
||||
type ListFilter struct {
|
||||
ID *string `json:"id"`
|
||||
Name *StringFilter `json:"name"`
|
||||
Tags *StringArrayFilter `json:"tags"`
|
||||
Maintainers *IDArrayFilter `json:"maintainers"`
|
||||
}
|
||||
|
||||
type ListSort struct {
|
||||
ID *SortRule `json:"id"`
|
||||
Name *SortRule `json:"name"`
|
||||
}
|
||||
|
||||
type Login struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type PageInfo struct {
|
||||
HasPreviousPage bool `json:"hasPreviousPage"`
|
||||
HasNextPage bool `json:"hasNextPage"`
|
||||
StartCursor string `json:"startCursor"`
|
||||
EndCursor string `json:"endCursor"`
|
||||
}
|
||||
|
||||
type SortRule struct {
|
||||
Direction SortDirection `json:"direction"`
|
||||
}
|
||||
|
||||
type StringArrayFilter struct {
|
||||
ContainsAll []*string `json:"containsAll"`
|
||||
ElemMatch *StringFilter `json:"elemMatch"`
|
||||
Length *int `json:"length"`
|
||||
}
|
||||
|
||||
type StringFilter struct {
|
||||
Eq *string `json:"eq"`
|
||||
Neq *string `json:"neq"`
|
||||
Regex *string `json:"regex"`
|
||||
}
|
||||
|
||||
type TimestampFilter struct {
|
||||
After *time.Time `json:"after"`
|
||||
Before *time.Time `json:"before"`
|
||||
}
|
||||
|
||||
type UserArrayFilter struct {
|
||||
ContainsAll []*UserFilter `json:"containsAll"`
|
||||
ContainsOne []*UserFilter `json:"containsOne"`
|
||||
Length *int `json:"length"`
|
||||
}
|
||||
|
||||
type UserConnection struct {
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
Edges []*UserEdge `json:"edges"`
|
||||
}
|
||||
|
||||
type UserEdge struct {
|
||||
Node *User `json:"node"`
|
||||
Cursor string `json:"cursor"`
|
||||
}
|
||||
|
||||
type UserFilter struct {
|
||||
ID *string `json:"id"`
|
||||
Username *StringFilter `json:"username"`
|
||||
MatrixLinks *StringArrayFilter `json:"matrixLinks"`
|
||||
PendingMatrixLinks *StringArrayFilter `json:"pendingMatrixLinks"`
|
||||
Admin *bool `json:"admin"`
|
||||
}
|
||||
|
||||
type UserSort struct {
|
||||
ID *SortRule `json:"id"`
|
||||
Username *SortRule `json:"username"`
|
||||
Admin *SortRule `json:"admin"`
|
||||
}
|
||||
|
||||
type SortDirection string
|
||||
|
||||
const (
|
||||
SortDirectionAsc SortDirection = "ASC"
|
||||
SortDirectionDesc SortDirection = "DESC"
|
||||
)
|
||||
|
||||
var AllSortDirection = []SortDirection{
|
||||
SortDirectionAsc,
|
||||
SortDirectionDesc,
|
||||
}
|
||||
|
||||
func (e SortDirection) IsValid() bool {
|
||||
switch e {
|
||||
case SortDirectionAsc, SortDirectionDesc:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e SortDirection) String() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
func (e *SortDirection) UnmarshalGQL(v interface{}) error {
|
||||
str, ok := v.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("enums must be strings")
|
||||
}
|
||||
|
||||
*e = SortDirection(str)
|
||||
if !e.IsValid() {
|
||||
return fmt.Errorf("%s is not a valid SortDirection", str)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e SortDirection) MarshalGQL(w io.Writer) {
|
||||
fmt.Fprint(w, strconv.Quote(e.String()))
|
||||
}
|
21
graph/model/user.go
Normal file
21
graph/model/user.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
package model
|
||||
|
||||
import model "github.com/Unkn0wnCat/matrix-veles/internal/db/model"
|
||||
|
||||
type User struct {
|
||||
ID string `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Admin *bool `json:"admin"`
|
||||
MatrixLinks []*string `json:"matrixLinks"`
|
||||
PendingMatrixLinks []*string `json:"pendingMatrixLinks"`
|
||||
}
|
||||
|
||||
func MakeUser(dbUser *model.DBUser) *User {
|
||||
return &User{
|
||||
ID: dbUser.ID.Hex(),
|
||||
Username: dbUser.Username,
|
||||
Admin: dbUser.Admin,
|
||||
MatrixLinks: dbUser.MatrixLinks,
|
||||
PendingMatrixLinks: dbUser.PendingMatrixLinks,
|
||||
}
|
||||
}
|
7
graph/resolver.go
Normal file
7
graph/resolver.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package graph
|
||||
|
||||
// This file will not be regenerated automatically.
|
||||
//
|
||||
// It serves as dependency injection for your app, add any dependencies you require here.
|
||||
|
||||
type Resolver struct{}
|
210
graph/schema.graphqls
Normal file
210
graph/schema.graphqls
Normal file
|
@ -0,0 +1,210 @@
|
|||
# GraphQL schema example
|
||||
#
|
||||
# https://gqlgen.com/getting-started/
|
||||
|
||||
scalar Time
|
||||
|
||||
directive @loggedIn on FIELD_DEFINITION
|
||||
|
||||
enum SortDirection {
|
||||
ASC
|
||||
DESC
|
||||
}
|
||||
|
||||
type PageInfo {
|
||||
hasPreviousPage: Boolean!
|
||||
hasNextPage: Boolean!
|
||||
startCursor: String!
|
||||
endCursor: String!
|
||||
}
|
||||
|
||||
input SortRule {
|
||||
direction: SortDirection!
|
||||
}
|
||||
|
||||
type User {
|
||||
id: ID!
|
||||
|
||||
username: String!
|
||||
|
||||
admin: Boolean
|
||||
|
||||
matrixLinks: [String!]
|
||||
pendingMatrixLinks: [String!]
|
||||
}
|
||||
|
||||
type UserConnection {
|
||||
pageInfo: PageInfo!
|
||||
edges: [UserEdge!]!
|
||||
}
|
||||
|
||||
type UserEdge {
|
||||
node: User!
|
||||
cursor: String!
|
||||
}
|
||||
|
||||
type Entry {
|
||||
id: ID!
|
||||
tags: [String!]
|
||||
partOf(first: Int, after: String): ListConnection
|
||||
hashValue: String!
|
||||
fileUrl: String
|
||||
timestamp: Time!
|
||||
addedBy: User!
|
||||
comments(first: Int, after: String): CommentConnection
|
||||
}
|
||||
|
||||
type EntryConnection {
|
||||
pageInfo: PageInfo!
|
||||
edges: [EntryEdge!]!
|
||||
}
|
||||
|
||||
type EntryEdge {
|
||||
node: Entry!
|
||||
cursor: String!
|
||||
}
|
||||
|
||||
type List {
|
||||
id: ID!
|
||||
name: String!
|
||||
tags: [String!]
|
||||
comments(first: Int, after: String): CommentConnection
|
||||
maintainers(first: Int, after: String): UserConnection!
|
||||
entries(first: Int, after: String): EntryConnection
|
||||
}
|
||||
|
||||
type ListConnection {
|
||||
pageInfo: PageInfo!
|
||||
edges: [ListEdge!]!
|
||||
}
|
||||
|
||||
type ListEdge {
|
||||
node: List!
|
||||
cursor: String!
|
||||
}
|
||||
|
||||
type Comment {
|
||||
timestamp: Time!
|
||||
author: User!
|
||||
content: String!
|
||||
}
|
||||
|
||||
type CommentConnection {
|
||||
pageInfo: PageInfo!
|
||||
edges: [CommentEdge!]!
|
||||
}
|
||||
|
||||
type CommentEdge {
|
||||
node: Comment!
|
||||
cursor: String!
|
||||
}
|
||||
|
||||
input IntFilter {
|
||||
gt: Int
|
||||
lt: Int
|
||||
eq: Int
|
||||
neq: Int
|
||||
}
|
||||
|
||||
input TimestampFilter {
|
||||
after: Time
|
||||
before: Time
|
||||
}
|
||||
|
||||
input StringFilter {
|
||||
eq: String # Equal
|
||||
neq: String # Not Equal
|
||||
regex: String # Regex Check
|
||||
}
|
||||
|
||||
input StringArrayFilter {
|
||||
containsAll: [String]
|
||||
elemMatch: StringFilter
|
||||
length: Int
|
||||
}
|
||||
|
||||
input UserFilter {
|
||||
id: ID
|
||||
username: StringFilter
|
||||
matrixLinks: StringArrayFilter
|
||||
pendingMatrixLinks: StringArrayFilter
|
||||
admin: Boolean
|
||||
}
|
||||
|
||||
input UserArrayFilter {
|
||||
containsAll: [UserFilter]
|
||||
containsOne: [UserFilter]
|
||||
length: Int
|
||||
}
|
||||
|
||||
input UserSort {
|
||||
id: SortRule
|
||||
username: SortRule
|
||||
admin: SortRule
|
||||
}
|
||||
|
||||
input ListFilter {
|
||||
id: ID
|
||||
name: StringFilter
|
||||
tags: StringArrayFilter
|
||||
maintainers: IDArrayFilter
|
||||
# entries: EntryArrayFilter
|
||||
}
|
||||
|
||||
input IDArrayFilter {
|
||||
containsAll: [ID]
|
||||
length: Int
|
||||
}
|
||||
|
||||
input ListArrayFilter {
|
||||
containsAll: [ListFilter]
|
||||
containsOne: [ListFilter]
|
||||
length: Int
|
||||
}
|
||||
|
||||
input ListSort {
|
||||
id: SortRule
|
||||
name: SortRule
|
||||
}
|
||||
|
||||
input EntryFilter {
|
||||
id: ID
|
||||
hashValue: StringFilter
|
||||
tags: StringArrayFilter
|
||||
addedBy: ID
|
||||
fileUrl: StringFilter
|
||||
timestamp: TimestampFilter
|
||||
partOf: IDArrayFilter
|
||||
}
|
||||
|
||||
input EntryArrayFilter {
|
||||
containsAll: [EntryFilter]
|
||||
containsOne: [EntryFilter]
|
||||
length: Int
|
||||
}
|
||||
|
||||
input EntrySort {
|
||||
id: SortRule
|
||||
hashValue: SortRule
|
||||
timestamp: SortRule
|
||||
addedBy: SortRule
|
||||
}
|
||||
|
||||
type Query {
|
||||
users(first: Int, after: String, filter: UserFilter, sort: UserSort): UserConnection! @loggedIn
|
||||
lists(first: Int, after: String, filter: ListFilter, sort: ListSort): ListConnection! @loggedIn
|
||||
entries(first: Int, after: String, filter: EntryFilter, sort: EntrySort): EntryConnection! @loggedIn
|
||||
|
||||
user(id: ID, username: String): User! @loggedIn
|
||||
entry(id: ID, hashValue: String): Entry! @loggedIn
|
||||
list(id: ID, name: String): List! @loggedIn
|
||||
}
|
||||
|
||||
input Login {
|
||||
username: String!
|
||||
password: String!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
login(input: Login!): String!
|
||||
}
|
687
graph/schema.resolvers.go
Normal file
687
graph/schema.resolvers.go
Normal file
|
@ -0,0 +1,687 @@
|
|||
package graph
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/Unkn0wnCat/matrix-veles/graph/generated"
|
||||
"github.com/Unkn0wnCat/matrix-veles/graph/model"
|
||||
"github.com/Unkn0wnCat/matrix-veles/internal/db"
|
||||
model2 "github.com/Unkn0wnCat/matrix-veles/internal/db/model"
|
||||
jwt "github.com/golang-jwt/jwt/v4"
|
||||
"github.com/spf13/viper"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
func (r *commentResolver) Author(ctx context.Context, obj *model.Comment) (*model.User, error) {
|
||||
user, err := db.GetUserByID(*obj.AuthorID)
|
||||
if err != nil {
|
||||
if errors.Is(err, mongo.ErrNoDocuments) {
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
return model.MakeUser(user), nil
|
||||
}
|
||||
|
||||
func (r *entryResolver) PartOf(ctx context.Context, obj *model.Entry, first *int, after *string) (*model.ListConnection, error) {
|
||||
ids := obj.PartOfIDs
|
||||
|
||||
if len(ids) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
startIndex := 0
|
||||
|
||||
if after != nil {
|
||||
afterInt := new(big.Int)
|
||||
afterInt.SetString(*after, 16)
|
||||
|
||||
idInt := new(big.Int)
|
||||
|
||||
set := false
|
||||
|
||||
for i, id := range obj.PartOfIDs {
|
||||
idInt.SetString(id.Hex(), 16)
|
||||
|
||||
if idInt.Cmp(afterInt) > 0 {
|
||||
startIndex = i
|
||||
set = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !set {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
if startIndex >= len(ids) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ids = ids[startIndex:]
|
||||
|
||||
length := 25
|
||||
|
||||
if first != nil {
|
||||
length = *first
|
||||
}
|
||||
|
||||
cut := false
|
||||
|
||||
if len(ids) > length {
|
||||
cut = true
|
||||
ids = ids[:length]
|
||||
}
|
||||
|
||||
var edges []*model.ListEdge
|
||||
|
||||
for _, id := range ids {
|
||||
dbList, err := db.GetListByID(*id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
edges = append(edges, &model.ListEdge{
|
||||
Node: model.MakeList(dbList),
|
||||
Cursor: dbList.ID.Hex(),
|
||||
})
|
||||
}
|
||||
|
||||
return &model.ListConnection{
|
||||
PageInfo: &model.PageInfo{
|
||||
HasPreviousPage: startIndex > 0,
|
||||
HasNextPage: cut,
|
||||
StartCursor: edges[0].Cursor,
|
||||
EndCursor: edges[len(edges)-1].Cursor,
|
||||
},
|
||||
Edges: edges,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *entryResolver) AddedBy(ctx context.Context, obj *model.Entry) (*model.User, error) {
|
||||
user, err := db.GetUserByID(obj.AddedByID)
|
||||
if err != nil {
|
||||
if errors.Is(err, mongo.ErrNoDocuments) {
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
return model.MakeUser(user), nil
|
||||
}
|
||||
|
||||
func (r *entryResolver) Comments(ctx context.Context, obj *model.Entry, first *int, after *string) (*model.CommentConnection, error) {
|
||||
comments := obj.RawComments
|
||||
|
||||
return ResolveComments(comments, first, after)
|
||||
}
|
||||
|
||||
func (r *listResolver) Comments(ctx context.Context, obj *model.List, first *int, after *string) (*model.CommentConnection, error) {
|
||||
comments := obj.RawComments
|
||||
|
||||
return ResolveComments(comments, first, after)
|
||||
}
|
||||
|
||||
func (r *listResolver) Maintainers(ctx context.Context, obj *model.List, first *int, after *string) (*model.UserConnection, error) {
|
||||
ids := obj.MaintainerIDs
|
||||
|
||||
if len(ids) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
startIndex := 0
|
||||
|
||||
if after != nil {
|
||||
afterInt := new(big.Int)
|
||||
afterInt.SetString(*after, 16)
|
||||
|
||||
idInt := new(big.Int)
|
||||
|
||||
set := false
|
||||
|
||||
for i, id := range ids {
|
||||
idInt.SetString(id.Hex(), 16)
|
||||
|
||||
if idInt.Cmp(afterInt) > 0 {
|
||||
startIndex = i
|
||||
set = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !set {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
if startIndex >= len(ids) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ids = ids[startIndex:]
|
||||
|
||||
length := 25
|
||||
|
||||
if first != nil {
|
||||
length = *first
|
||||
}
|
||||
|
||||
cut := false
|
||||
|
||||
if len(ids) > length {
|
||||
cut = true
|
||||
ids = ids[:length]
|
||||
}
|
||||
|
||||
var edges []*model.UserEdge
|
||||
|
||||
for _, id := range ids {
|
||||
dbUser, err := db.GetUserByID(*id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
edges = append(edges, &model.UserEdge{
|
||||
Node: model.MakeUser(dbUser),
|
||||
Cursor: dbUser.ID.Hex(),
|
||||
})
|
||||
}
|
||||
|
||||
return &model.UserConnection{
|
||||
PageInfo: &model.PageInfo{
|
||||
HasPreviousPage: startIndex > 0,
|
||||
HasNextPage: cut,
|
||||
StartCursor: edges[0].Cursor,
|
||||
EndCursor: edges[len(edges)-1].Cursor,
|
||||
},
|
||||
Edges: edges,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *listResolver) Entries(ctx context.Context, obj *model.List, first *int, after *string) (*model.EntryConnection, error) {
|
||||
coll := db.Db.Collection(viper.GetString("bot.mongo.collection.entries"))
|
||||
|
||||
dbFilter, _, dbLimit, err := buildDBEntryFilter(first, after, &model.EntryFilter{
|
||||
PartOf: &model.IDArrayFilter{
|
||||
ContainsAll: []*string{&obj.ID},
|
||||
},
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newLimit := *dbLimit + 1
|
||||
|
||||
findOpts := options.FindOptions{
|
||||
Limit: &newLimit,
|
||||
}
|
||||
|
||||
res, err := coll.Find(ctx, *dbFilter, &findOpts)
|
||||
if err != nil {
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
var rawEntries []model2.DBEntry
|
||||
|
||||
err = res.All(ctx, &rawEntries)
|
||||
if err != nil {
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
if len(rawEntries) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
lastEntryI := len(rawEntries) - 1
|
||||
if lastEntryI > 0 {
|
||||
lastEntryI--
|
||||
}
|
||||
|
||||
firstEntry := rawEntries[0]
|
||||
lastEntry := rawEntries[lastEntryI]
|
||||
|
||||
isAfter := false
|
||||
|
||||
if after != nil {
|
||||
isAfter = true
|
||||
}
|
||||
|
||||
hasMore := false
|
||||
if int64(len(rawEntries)) > *dbLimit {
|
||||
hasMore = true
|
||||
}
|
||||
|
||||
var edges []*model.EntryEdge
|
||||
|
||||
for i, rawEntry := range rawEntries {
|
||||
if int64(i) == *dbLimit {
|
||||
continue
|
||||
}
|
||||
|
||||
edges = append(edges, &model.EntryEdge{
|
||||
Node: model.MakeEntry(&rawEntry),
|
||||
Cursor: rawEntry.ID.Hex(),
|
||||
})
|
||||
}
|
||||
|
||||
return &model.EntryConnection{
|
||||
PageInfo: &model.PageInfo{
|
||||
HasPreviousPage: isAfter,
|
||||
HasNextPage: hasMore,
|
||||
StartCursor: firstEntry.ID.Hex(),
|
||||
EndCursor: lastEntry.ID.Hex(),
|
||||
},
|
||||
Edges: edges,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) Login(ctx context.Context, input model.Login) (string, error) {
|
||||
user, err := db.GetUserByUsername(input.Username)
|
||||
if err != nil {
|
||||
if errors.Is(err, mongo.ErrNoDocuments) {
|
||||
return "", errors.New("invalid credentials")
|
||||
}
|
||||
|
||||
return "", errors.New("database error")
|
||||
}
|
||||
|
||||
err = user.CheckPassword(input.Password)
|
||||
if err != nil {
|
||||
return "", errors.New("invalid credentials")
|
||||
}
|
||||
|
||||
jwtSigningKey := []byte(viper.GetString("bot.web.secret"))
|
||||
|
||||
claims := model2.JwtClaims{
|
||||
Username: user.Username,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24 * 365 * 100)),
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
NotBefore: jwt.NewNumericDate(time.Now()),
|
||||
Issuer: "veles-api",
|
||||
Subject: user.ID.Hex(),
|
||||
},
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
ss, err := token.SignedString(jwtSigningKey)
|
||||
if err != nil {
|
||||
return "", errors.New("unable to create token")
|
||||
}
|
||||
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) Users(ctx context.Context, first *int, after *string, filter *model.UserFilter, sort *model.UserSort) (*model.UserConnection, error) {
|
||||
dbFilter, dbSort, dbLimit, err := buildDBUserFilter(first, after, filter, sort)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
coll := db.Db.Collection(viper.GetString("bot.mongo.collection.users"))
|
||||
|
||||
newLimit := *dbLimit + 1
|
||||
|
||||
findOpts := options.FindOptions{
|
||||
Limit: &newLimit,
|
||||
Sort: *dbSort,
|
||||
}
|
||||
|
||||
res, err := coll.Find(ctx, *dbFilter, &findOpts)
|
||||
if err != nil {
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
var rawUsers []model2.DBUser
|
||||
|
||||
err = res.All(ctx, &rawUsers)
|
||||
if err != nil {
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
if len(rawUsers) == 0 {
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
lastUserI := len(rawUsers) - 1
|
||||
if lastUserI > 0 {
|
||||
lastUserI--
|
||||
}
|
||||
|
||||
firstUser := rawUsers[0]
|
||||
lastUser := rawUsers[lastUserI]
|
||||
|
||||
isAfter := false
|
||||
|
||||
if after != nil {
|
||||
isAfter = true
|
||||
}
|
||||
|
||||
hasMore := false
|
||||
if int64(len(rawUsers)) > *dbLimit {
|
||||
hasMore = true
|
||||
}
|
||||
|
||||
var edges []*model.UserEdge
|
||||
|
||||
for i, rawUser := range rawUsers {
|
||||
if int64(i) == *dbLimit {
|
||||
continue
|
||||
}
|
||||
|
||||
edges = append(edges, &model.UserEdge{
|
||||
Node: model.MakeUser(&rawUser),
|
||||
Cursor: rawUser.ID.Hex(),
|
||||
})
|
||||
}
|
||||
|
||||
return &model.UserConnection{
|
||||
PageInfo: &model.PageInfo{
|
||||
HasPreviousPage: isAfter,
|
||||
HasNextPage: hasMore,
|
||||
StartCursor: firstUser.ID.Hex(),
|
||||
EndCursor: lastUser.ID.Hex(),
|
||||
},
|
||||
Edges: edges,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) Lists(ctx context.Context, first *int, after *string, filter *model.ListFilter, sort *model.ListSort) (*model.ListConnection, error) {
|
||||
dbFilter, dbSort, dbLimit, err := buildDBListFilter(first, after, filter, sort)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
coll := db.Db.Collection(viper.GetString("bot.mongo.collection.lists"))
|
||||
|
||||
newLimit := *dbLimit + 1
|
||||
|
||||
findOpts := options.FindOptions{
|
||||
Limit: &newLimit,
|
||||
Sort: *dbSort,
|
||||
}
|
||||
|
||||
res, err := coll.Find(ctx, *dbFilter, &findOpts)
|
||||
if err != nil {
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
var rawLists []model2.DBHashList
|
||||
|
||||
err = res.All(ctx, &rawLists)
|
||||
if err != nil {
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
if len(rawLists) == 0 {
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
lastListI := len(rawLists) - 1
|
||||
if lastListI > 0 {
|
||||
lastListI--
|
||||
}
|
||||
|
||||
firstList := rawLists[0]
|
||||
lastList := rawLists[lastListI]
|
||||
|
||||
isAfter := false
|
||||
|
||||
if after != nil {
|
||||
isAfter = true
|
||||
}
|
||||
|
||||
hasMore := false
|
||||
if int64(len(rawLists)) > *dbLimit {
|
||||
hasMore = true
|
||||
}
|
||||
|
||||
var edges []*model.ListEdge
|
||||
|
||||
for i, rawList := range rawLists {
|
||||
if int64(i) == *dbLimit {
|
||||
continue
|
||||
}
|
||||
|
||||
edges = append(edges, &model.ListEdge{
|
||||
Node: model.MakeList(&rawList),
|
||||
Cursor: rawList.ID.Hex(),
|
||||
})
|
||||
}
|
||||
|
||||
return &model.ListConnection{
|
||||
PageInfo: &model.PageInfo{
|
||||
HasPreviousPage: isAfter,
|
||||
HasNextPage: hasMore,
|
||||
StartCursor: firstList.ID.Hex(),
|
||||
EndCursor: lastList.ID.Hex(),
|
||||
},
|
||||
Edges: edges,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) Entries(ctx context.Context, first *int, after *string, filter *model.EntryFilter, sort *model.EntrySort) (*model.EntryConnection, error) {
|
||||
dbFilter, dbSort, dbLimit, err := buildDBEntryFilter(first, after, filter, sort)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
coll := db.Db.Collection(viper.GetString("bot.mongo.collection.entries"))
|
||||
|
||||
newLimit := *dbLimit + 1
|
||||
|
||||
findOpts := options.FindOptions{
|
||||
Limit: &newLimit,
|
||||
Sort: *dbSort,
|
||||
}
|
||||
|
||||
res, err := coll.Find(ctx, *dbFilter, &findOpts)
|
||||
if err != nil {
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
var rawEntries []model2.DBEntry
|
||||
|
||||
err = res.All(ctx, &rawEntries)
|
||||
if err != nil {
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
if len(rawEntries) == 0 {
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
lastEntryI := len(rawEntries) - 1
|
||||
if lastEntryI > 0 {
|
||||
lastEntryI--
|
||||
}
|
||||
|
||||
firstEntry := rawEntries[0]
|
||||
lastEntry := rawEntries[lastEntryI]
|
||||
|
||||
isAfter := false
|
||||
|
||||
if after != nil {
|
||||
isAfter = true
|
||||
}
|
||||
|
||||
hasMore := false
|
||||
if int64(len(rawEntries)) > *dbLimit {
|
||||
hasMore = true
|
||||
}
|
||||
|
||||
var edges []*model.EntryEdge
|
||||
|
||||
for i, rawEntry := range rawEntries {
|
||||
if int64(i) == *dbLimit {
|
||||
continue
|
||||
}
|
||||
|
||||
edges = append(edges, &model.EntryEdge{
|
||||
Node: model.MakeEntry(&rawEntry),
|
||||
Cursor: rawEntry.ID.Hex(),
|
||||
})
|
||||
}
|
||||
|
||||
return &model.EntryConnection{
|
||||
PageInfo: &model.PageInfo{
|
||||
HasPreviousPage: isAfter,
|
||||
HasNextPage: hasMore,
|
||||
StartCursor: firstEntry.ID.Hex(),
|
||||
EndCursor: lastEntry.ID.Hex(),
|
||||
},
|
||||
Edges: edges,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) User(ctx context.Context, id *string, username *string) (*model.User, error) {
|
||||
if id != nil {
|
||||
dbId, err := primitive.ObjectIDFromHex(*id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rawUser, err := db.GetUserByID(dbId)
|
||||
if err != nil {
|
||||
if errors.Is(err, mongo.ErrNoDocuments) {
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
return model.MakeUser(rawUser), nil
|
||||
}
|
||||
|
||||
if username != nil {
|
||||
rawUser, err := db.GetUserByUsername(*username)
|
||||
if err != nil {
|
||||
if errors.Is(err, mongo.ErrNoDocuments) {
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
return model.MakeUser(rawUser), nil
|
||||
}
|
||||
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
func (r *queryResolver) Entry(ctx context.Context, id *string, hashValue *string) (*model.Entry, error) {
|
||||
if id != nil {
|
||||
dbId, err := primitive.ObjectIDFromHex(*id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rawEntry, err := db.GetEntryByID(dbId)
|
||||
if err != nil {
|
||||
if errors.Is(err, mongo.ErrNoDocuments) {
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
return model.MakeEntry(rawEntry), nil
|
||||
}
|
||||
|
||||
if hashValue != nil {
|
||||
rawEntry, err := db.GetEntryByHash(*hashValue)
|
||||
if err != nil {
|
||||
if errors.Is(err, mongo.ErrNoDocuments) {
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
return model.MakeEntry(rawEntry), nil
|
||||
}
|
||||
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
func (r *queryResolver) List(ctx context.Context, id *string, name *string) (*model.List, error) {
|
||||
if id != nil {
|
||||
dbId, err := primitive.ObjectIDFromHex(*id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rawList, err := db.GetListByID(dbId)
|
||||
if err != nil {
|
||||
if errors.Is(err, mongo.ErrNoDocuments) {
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
return model.MakeList(rawList), nil
|
||||
}
|
||||
|
||||
if name != nil {
|
||||
rawList, err := db.GetListByName(*name)
|
||||
if err != nil {
|
||||
if errors.Is(err, mongo.ErrNoDocuments) {
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
return nil, errors.New("database error")
|
||||
}
|
||||
|
||||
return model.MakeList(rawList), nil
|
||||
}
|
||||
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
// Comment returns generated.CommentResolver implementation.
|
||||
func (r *Resolver) Comment() generated.CommentResolver { return &commentResolver{r} }
|
||||
|
||||
// Entry returns generated.EntryResolver implementation.
|
||||
func (r *Resolver) Entry() generated.EntryResolver { return &entryResolver{r} }
|
||||
|
||||
// List returns generated.ListResolver implementation.
|
||||
func (r *Resolver) List() generated.ListResolver { return &listResolver{r} }
|
||||
|
||||
// Mutation returns generated.MutationResolver implementation.
|
||||
func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} }
|
||||
|
||||
// Query returns generated.QueryResolver implementation.
|
||||
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
|
||||
|
||||
type commentResolver struct{ *Resolver }
|
||||
type entryResolver struct{ *Resolver }
|
||||
type listResolver struct{ *Resolver }
|
||||
type mutationResolver struct{ *Resolver }
|
||||
type queryResolver struct{ *Resolver }
|
||||
|
||||
// !!! WARNING !!!
|
||||
// The code below was going to be deleted when updating resolvers. It has been copied here so you have
|
||||
// one last chance to move it out of harms way if you want. There are two reasons this happens:
|
||||
// - When renaming or deleting a resolver the old code will be put in here. You can safely delete
|
||||
// it when you're done.
|
||||
// - You have helper methods in this file. Move them out to keep these resolver files clean.
|
||||
func (r *commentResolver) Timestamp(ctx context.Context, obj *model.Comment) (*time.Time, error) {
|
||||
panic(fmt.Errorf("not implemented"))
|
||||
}
|
||||
func (r *entryResolver) Timestamp(ctx context.Context, obj *model.Entry) (*time.Time, error) {
|
||||
panic(fmt.Errorf("not implemented"))
|
||||
}
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/spf13/viper"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/event"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"log"
|
||||
|
@ -13,6 +14,7 @@ import (
|
|||
)
|
||||
|
||||
var DbClient *mongo.Client
|
||||
var Db *mongo.Database
|
||||
|
||||
func Connect() {
|
||||
if viper.GetString("bot.mongo.uri") == "" {
|
||||
|
@ -20,15 +22,22 @@ func Connect() {
|
|||
return
|
||||
}
|
||||
|
||||
cmdMonitor := &event.CommandMonitor{
|
||||
Started: func(_ context.Context, evt *event.CommandStartedEvent) {
|
||||
log.Print(evt.Command)
|
||||
},
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
newClient, err := mongo.Connect(ctx, options.Client().ApplyURI(viper.GetString("bot.mongo.uri")))
|
||||
newClient, err := mongo.Connect(ctx, options.Client().ApplyURI(viper.GetString("bot.mongo.uri")).SetMonitor(cmdMonitor))
|
||||
if err != nil {
|
||||
log.Println("Could not connect to DB")
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
DbClient = newClient
|
||||
Db = DbClient.Database(viper.GetString("bot.mongo.database"))
|
||||
}
|
||||
|
||||
func SaveEntry(entry *model.DBEntry) error {
|
||||
|
|
8
internal/db/model/jwtClaims.go
Normal file
8
internal/db/model/jwtClaims.go
Normal file
|
@ -0,0 +1,8 @@
|
|||
package model
|
||||
|
||||
import "github.com/golang-jwt/jwt/v4"
|
||||
|
||||
type JwtClaims struct {
|
||||
Username string `json:"username"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
|
@ -5,6 +5,12 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
chiprometheus "github.com/766b/chi-prometheus"
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/99designs/gqlgen/graphql/handler"
|
||||
"github.com/99designs/gqlgen/graphql/playground"
|
||||
"github.com/Unkn0wnCat/matrix-veles/graph"
|
||||
"github.com/Unkn0wnCat/matrix-veles/graph/generated"
|
||||
"github.com/Unkn0wnCat/matrix-veles/internal/db/model"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/cors"
|
||||
"net/http"
|
||||
|
@ -25,10 +31,30 @@ func SetupAPI() chi.Router {
|
|||
|
||||
m := chiprometheus.NewMiddleware("api")
|
||||
router.Use(m)
|
||||
router.Use(decodeAuthMiddleware)
|
||||
|
||||
router.NotFound(notFoundHandler)
|
||||
router.MethodNotAllowed(methodNotAllowedHandler)
|
||||
|
||||
router.Handle("/", playground.Handler("GraphQL playground", "/api/query"))
|
||||
|
||||
c := generated.Config{Resolvers: &graph.Resolver{}}
|
||||
c.Directives.LoggedIn = func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) {
|
||||
claimsVal := ctx.Value("claims")
|
||||
var claims model.JwtClaims
|
||||
if claimsVal != nil {
|
||||
claims = claimsVal.(model.JwtClaims)
|
||||
if claims.Valid() == nil {
|
||||
return next(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New("authentication required")
|
||||
}
|
||||
|
||||
srv := handler.NewDefaultServer(generated.NewExecutableSchema(c))
|
||||
router.Handle("/query", srv)
|
||||
|
||||
//router.NotFoundHandler = NotFoundHandler{}
|
||||
//router.MethodNotAllowedHandler = MethodNotAllowedHandler{}
|
||||
|
||||
|
@ -72,7 +98,7 @@ func SetupAPI() chi.Router {
|
|||
r.Get("/", func(writer http.ResponseWriter, request *http.Request) {
|
||||
writer.WriteHeader(200)
|
||||
|
||||
claims := request.Context().Value("claims").(jwtClaims)
|
||||
claims := request.Context().Value("claims").(model.JwtClaims)
|
||||
|
||||
writer.Write([]byte(`hello ` + claims.Username))
|
||||
})
|
||||
|
@ -81,12 +107,38 @@ func SetupAPI() chi.Router {
|
|||
return router
|
||||
}
|
||||
|
||||
func getClaims(request *http.Request) jwtClaims {
|
||||
claims := request.Context().Value("claims").(jwtClaims)
|
||||
func getClaims(request *http.Request) model.JwtClaims {
|
||||
claims := request.Context().Value("claims").(model.JwtClaims)
|
||||
|
||||
return claims
|
||||
}
|
||||
|
||||
func decodeAuthMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
|
||||
token := req.Header.Get("Authorization")
|
||||
tokenSplit := strings.Split(token, " ")
|
||||
|
||||
if token == "" || len(tokenSplit) < 2 {
|
||||
next.ServeHTTP(res, req)
|
||||
return
|
||||
}
|
||||
|
||||
token = tokenSplit[1]
|
||||
|
||||
claims, _, err := parseToken(token)
|
||||
if err != nil {
|
||||
next.ServeHTTP(res, req)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(req.Context(), "claims", *claims)
|
||||
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
next.ServeHTTP(res, req)
|
||||
})
|
||||
}
|
||||
|
||||
func checkAuthMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
|
||||
token := req.Header.Get("Authorization")
|
||||
|
|
|
@ -18,13 +18,8 @@ type apiAuthRequestBody struct {
|
|||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type jwtClaims struct {
|
||||
Username string `json:"username"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
func parseToken(tokenString string) (*jwtClaims, *jwt.Token, error) {
|
||||
claims := jwtClaims{}
|
||||
func parseToken(tokenString string) (*model.JwtClaims, *jwt.Token, error) {
|
||||
claims := model.JwtClaims{}
|
||||
jwtSigningKey := []byte(viper.GetString("bot.web.secret"))
|
||||
|
||||
token, err := jwt.ParseWithClaims(tokenString, &claims, func(token *jwt.Token) (interface{}, error) {
|
||||
|
@ -67,7 +62,7 @@ func apiHandleAuthLogin(res http.ResponseWriter, req *http.Request) {
|
|||
|
||||
jwtSigningKey := []byte(viper.GetString("bot.web.secret"))
|
||||
|
||||
claims := jwtClaims{
|
||||
claims := model.JwtClaims{
|
||||
Username: user.Username,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24 * 365 * 100)),
|
||||
|
@ -143,7 +138,7 @@ func apiHandleAuthRegister(res http.ResponseWriter, req *http.Request) {
|
|||
|
||||
jwtSigningKey := viper.GetString("bot.web.secret")
|
||||
|
||||
claims := jwtClaims{
|
||||
claims := model.JwtClaims{
|
||||
Username: user.Username,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24)),
|
||||
|
|
2
main.go
2
main.go
|
@ -17,6 +17,8 @@
|
|||
|
||||
package main
|
||||
|
||||
//go:generate gqlgen generate
|
||||
|
||||
import (
|
||||
"github.com/Unkn0wnCat/matrix-veles/cmd"
|
||||
)
|
||||
|
|
8
tools.go
Normal file
8
tools.go
Normal file
|
@ -0,0 +1,8 @@
|
|||
//go:build tools
|
||||
// +build tools
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "github.com/99designs/gqlgen"
|
||||
)
|
Loading…
Add table
Reference in a new issue